Merge "Fix notification gestures." into jb-dev

This commit is contained in:
Daniel Sandler
2012-09-11 21:18:17 -07:00
committed by Android (Google) Code Review
3 changed files with 144 additions and 103 deletions

View File

@ -67,6 +67,6 @@
<integer translatable="false" name="config_search_panel_view_vibration_duration">20</integer>
<!-- The length of the vibration when the notificaiotn pops open. -->
<integer name="one_finger_pop_duration_ms">10</integer>
<integer name="blinds_pop_duration_ms">10</integer>
</resources>

View File

@ -152,5 +152,8 @@
<dimen name="carrier_label_height">24dp</dimen>
<!-- The distance you can pull a notificaiton before it pops open -->
<dimen name="one_finger_pop_limit">32dp</dimen>
<dimen name="blinds_pop_threshold">32dp</dimen>
<!-- The size of the gesture span needed to activate the "pull" notification expansion -->
<dimen name="pull_span_min">25dp</dimen>
</resources>

View File

@ -50,7 +50,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
private static final long EXPAND_DURATION = 250;
private static final long GLOW_DURATION = 150;
// Set to false to disable focus-based gestures (two-finger pull).
// Set to false to disable focus-based gestures (spread-finger vertical pull).
private static final boolean USE_DRAG = true;
// Set to false to disable scale-based gestures (both horizontal and vertical).
private static final boolean USE_SPAN = true;
@ -69,8 +69,12 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
@SuppressWarnings("unused")
private Context mContext;
private boolean mStretching;
private boolean mPullingWithOneFinger;
private boolean mExpanding;
private static final int NONE = 0;
private static final int BLINDS = 1<<0;
private static final int PULL = 1<<1;
private static final int STRETCH = 1<<2;
private int mExpansionStyle = NONE;
private boolean mWatchingForPull;
private boolean mHasPopped;
private View mEventSource;
@ -86,8 +90,9 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
private int mLastMotionY;
private float mPopLimit;
private int mPopDuration;
private float mPullGestureMinXSpan;
private Callback mCallback;
private ScaleGestureDetector mDetector;
private ScaleGestureDetector mSGD;
private ViewScaler mScaler;
private ObjectAnimator mScaleAnimation;
private AnimatorSet mGlowAnimationSet;
@ -122,7 +127,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
if (height < 0) {
height = mView.getMeasuredHeight();
}
return (float) height;
return height;
}
public int getNaturalHeight(int maximum) {
ViewGroup.LayoutParams lp = mView.getLayoutParams();
@ -161,8 +166,9 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
mGravity = Gravity.TOP;
mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f);
mScaleAnimation.setDuration(EXPAND_DURATION);
mPopLimit = mContext.getResources().getDimension(R.dimen.one_finger_pop_limit);
mPopDuration = mContext.getResources().getInteger(R.integer.one_finger_pop_duration_ms);
mPopLimit = mContext.getResources().getDimension(R.dimen.blinds_pop_threshold);
mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms);
mPullGestureMinXSpan = mContext.getResources().getDimension(R.dimen.pull_span_min);
AnimatorListenerAdapter glowVisibilityController = new AnimatorListenerAdapter() {
@Override
@ -193,41 +199,30 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
final ViewConfiguration configuration = ViewConfiguration.get(mContext);
mTouchSlop = configuration.getScaledTouchSlop();
mDetector =
new ScaleGestureDetector(context,
mSGD = new ScaleGestureDetector(context,
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
if (DEBUG_SCALE) Slog.v(TAG, "onscalebegin()");
float x = detector.getFocusX();
float y = detector.getFocusY();
float focusX = detector.getFocusX();
float focusY = detector.getFocusY();
// your fingers have to be somewhat close to the bounds of the view in question
mInitialTouchFocusY = detector.getFocusY();
mInitialTouchFocusY = focusY;
mInitialTouchSpan = Math.abs(detector.getCurrentSpan());
if (DEBUG_SCALE) Slog.d(TAG, "got mInitialTouchSpan: (" + mInitialTouchSpan + ")");
mStretching = initScale(findView(x, y));
return mStretching;
final View underFocus = findView(focusX, focusY);
if (underFocus != null) {
startExpanding(underFocus, STRETCH);
}
return mExpanding;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
if (DEBUG_SCALE) Slog.v(TAG, "onscale() on " + mCurrView);
// are we scaling or dragging?
float span = Math.abs(detector.getCurrentSpan()) - mInitialTouchSpan;
span *= USE_SPAN ? 1f : 0f;
float drag = detector.getFocusY() - mInitialTouchFocusY;
drag *= USE_DRAG ? 1f : 0f;
drag *= mGravity == Gravity.BOTTOM ? -1f : 1f;
float pull = Math.abs(drag) + Math.abs(span) + 1f;
float hand = drag * Math.abs(drag) / pull + span * Math.abs(span) / pull;
float target = hand + mOldHeight;
float newHeight = clamp(target);
mScaler.setHeight(newHeight);
setGlow(calculateGlow(target, newHeight));
updateExpansion();
return true;
}
@ -236,13 +231,28 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
if (DEBUG_SCALE) Slog.v(TAG, "onscaleend()");
// I guess we're alone now
if (DEBUG_SCALE) Slog.d(TAG, "scale end");
finishScale(false);
finishExpanding(false);
clearView();
mStretching = false;
}
});
}
private void updateExpansion() {
// are we scaling or dragging?
float span = Math.abs(mSGD.getCurrentSpan()) - mInitialTouchSpan;
span *= USE_SPAN ? 1f : 0f;
float drag = mSGD.getFocusY() - mInitialTouchFocusY;
drag *= USE_DRAG ? 1f : 0f;
drag *= mGravity == Gravity.BOTTOM ? -1f : 1f;
float pull = Math.abs(drag) + Math.abs(span) + 1f;
float hand = drag * Math.abs(drag) / pull + span * Math.abs(span) / pull;
float target = hand + mOldHeight;
float newHeight = clamp(target);
mScaler.setHeight(newHeight);
setGlow(calculateGlow(target, newHeight));
}
private float clamp(float target) {
float out = target;
out = out < mSmallSize ? mSmallSize : (out > mLargeSize ? mLargeSize : out);
@ -255,8 +265,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
if (mEventSource != null) {
int[] location = new int[2];
mEventSource.getLocationOnScreen(location);
x += (float) location[0];
y += (float) location[1];
x += location[0];
y += location[1];
v = mCallback.getChildAtRawPosition(x, y);
} else {
v = mCallback.getChildAtPosition(x, y);
@ -274,14 +284,14 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
if (mEventSource != null) {
int[] location = new int[2];
mEventSource.getLocationOnScreen(location);
x += (float) location[0];
y += (float) location[1];
x += location[0];
y += location[1];
if (DEBUG) Slog.d(TAG, " to global (" + x + ", " + y + ")");
}
int[] location = new int[2];
v.getLocationOnScreen(location);
x -= (float) location[0];
y -= (float) location[1];
x -= location[0];
y -= location[1];
if (DEBUG) Slog.d(TAG, " to local (" + x + ", " + y + ")");
if (DEBUG) Slog.d(TAG, " inside (" + v.getWidth() + ", " + v.getHeight() + ")");
boolean inside = (x > 0f && y > 0f && x < v.getWidth() & y < v.getHeight());
@ -303,7 +313,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
private float calculateGlow(float target, float actual) {
// glow if overscale
if (DEBUG_GLOW) Slog.d(TAG, "target: " + target + " actual: " + actual);
float stretch = (float) Math.abs((target - actual) / mMaximumStretch);
float stretch = Math.abs((target - actual) / mMaximumStretch);
float strength = 1f / (1f + (float) Math.pow(Math.E, -1 * ((8f * stretch) - 5f)));
if (DEBUG_GLOW) Slog.d(TAG, "stretch: " + stretch + " strength: " + strength);
return (GLOW_BASE + strength * (1f - GLOW_BASE));
@ -340,32 +350,54 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
View.INVISIBLE : View.VISIBLE);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (DEBUG) Slog.d(TAG, "interceptTouch: act=" + (ev.getAction()) +
" stretching=" + mStretching +
" onefinger=" + mPullingWithOneFinger);
// check for a two-finger gesture
mDetector.onTouchEvent(ev);
if (mStretching) {
final int action = ev.getAction();
if (DEBUG_SCALE) Slog.d(TAG, "intercept: act=" + MotionEvent.actionToString(action) +
" expanding=" + mExpanding +
(0 != (mExpansionStyle & BLINDS) ? " (blinds)" : "") +
(0 != (mExpansionStyle & PULL) ? " (pull)" : "") +
(0 != (mExpansionStyle & STRETCH) ? " (stretch)" : ""));
// check for a spread-finger vertical pull gesture
mSGD.onTouchEvent(ev);
final int x = (int) mSGD.getFocusX();
final int y = (int) mSGD.getFocusY();
if (mExpanding) {
return true;
} else {
final int action = ev.getAction();
if ((action == MotionEvent.ACTION_MOVE) && mPullingWithOneFinger) {
if ((action == MotionEvent.ACTION_MOVE) && 0 != (mExpansionStyle & BLINDS)) {
// we've begun Venetian blinds style expansion
return true;
}
final float xspan = mSGD.getCurrentSpanX();
if ((action == MotionEvent.ACTION_MOVE &&
xspan > mPullGestureMinXSpan &&
xspan > mSGD.getCurrentSpanY())) {
// detect a vertical pulling gesture with fingers somewhat separated
if (DEBUG_SCALE) Slog.v(TAG, "got pull gesture (xspan=" + xspan + "px)");
mInitialTouchFocusY = y;
final View underFocus = findView(x, y);
if (underFocus != null) {
startExpanding(underFocus, PULL);
}
return true;
}
if (mScrollView != null && mScrollView.getScrollY() > 0) {
return false;
}
// Now look for other gestures
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_MOVE: {
if (mWatchingForPull) {
final int x = (int) ev.getX();
final int y = (int) ev.getY();
final int yDiff = y - mLastMotionY;
if (yDiff > mTouchSlop) {
if (DEBUG) Slog.v(TAG, "got venetian gesture (dy=" + yDiff + "px)");
mLastMotionY = y;
mPullingWithOneFinger = initScale(findView(x, y));
if (mPullingWithOneFinger) {
final View underFocus = findView(x, y);
if (underFocus != null) {
startExpanding(underFocus, BLINDS);
mInitialTouchY = mLastMotionY;
mHasPopped = false;
}
@ -375,35 +407,35 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
}
case MotionEvent.ACTION_DOWN:
mWatchingForPull = isInside(mScrollView, ev.getX(), ev.getY());
mLastMotionY = (int) ev.getY();
mWatchingForPull = isInside(mScrollView, x, y);
mLastMotionY = y;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (mPullingWithOneFinger) {
finishScale(false);
clearView();
}
mPullingWithOneFinger = false;
mWatchingForPull = false;
if (DEBUG) Slog.d(TAG, "up/cancel");
finishExpanding(false);
clearView();
break;
}
return mPullingWithOneFinger;
return mExpanding;
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
if (DEBUG_SCALE) Slog.d(TAG, "touch: act=" + (action) +
" stretching=" + mStretching +
" onefinger=" + mPullingWithOneFinger);
if (mStretching) {
mDetector.onTouchEvent(ev);
}
if (DEBUG_SCALE) Slog.d(TAG, "touch: act=" + MotionEvent.actionToString(action) +
" expanding=" + mExpanding +
(0 != (mExpansionStyle & BLINDS) ? " (blinds)" : "") +
(0 != (mExpansionStyle & PULL) ? " (pull)" : "") +
(0 != (mExpansionStyle & STRETCH) ? " (stretch)" : ""));
mSGD.onTouchEvent(ev);
switch (action) {
case MotionEvent.ACTION_MOVE: {
if (mPullingWithOneFinger) {
if (0 != (mExpansionStyle & BLINDS)) {
final float rawHeight = ev.getY() - mInitialTouchY + mOldHeight;
final float newHeight = clamp(rawHeight);
final boolean wasClosed = (mOldHeight == mSmallSize);
@ -430,57 +462,59 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
setGlow(calculateGlow(4f * pull, 0f));
}
final int x = (int) ev.getX();
final int y = (int) ev.getY();
View underPointer = findView(x, y);
if (isFinished && underPointer != null && underPointer != mCurrView) {
finishScale(false);
initScale(underPointer);
mInitialTouchY = ev.getY();
final int x = (int) mSGD.getFocusX();
final int y = (int) mSGD.getFocusY();
View underFocus = findView(x, y);
if (isFinished && underFocus != null && underFocus != mCurrView) {
finishExpanding(false); // @@@ needed?
startExpanding(underFocus, BLINDS);
mInitialTouchY = y;
mHasPopped = false;
}
return true;
}
if (mExpanding) {
updateExpansion();
return true;
}
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (DEBUG) Slog.d(TAG, "cancel");
mStretching = false;
if (mPullingWithOneFinger) {
finishScale(false);
mPullingWithOneFinger = false;
}
if (DEBUG) Slog.d(TAG, "up/cancel");
finishExpanding(false);
clearView();
break;
}
return true;
}
private boolean initScale(View v) {
if (v != null) {
if (DEBUG) Slog.d(TAG, "scale begins on view: " + v);
mCallback.setUserLockedChild(v, true);
setView(v);
setGlow(GLOW_BASE);
mScaler.setView(v);
mOldHeight = mScaler.getHeight();
if (mCallback.canChildBeExpanded(v)) {
if (DEBUG) Slog.d(TAG, "working on an expandable child");
mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
} else {
if (DEBUG) Slog.d(TAG, "working on a non-expandable child");
mNaturalHeight = mOldHeight;
}
if (DEBUG) Slog.d(TAG, "got mOldHeight: " + mOldHeight +
" mNaturalHeight: " + mNaturalHeight);
v.getParent().requestDisallowInterceptTouchEvent(true);
return true;
private void startExpanding(View v, int expandType) {
mExpanding = true;
mExpansionStyle = expandType;
if (DEBUG) Slog.d(TAG, "scale type " + expandType + " beginning on view: " + v);
mCallback.setUserLockedChild(v, true);
setView(v);
setGlow(GLOW_BASE);
mScaler.setView(v);
mOldHeight = mScaler.getHeight();
if (mCallback.canChildBeExpanded(v)) {
if (DEBUG) Slog.d(TAG, "working on an expandable child");
mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
} else {
return false;
if (DEBUG) Slog.d(TAG, "working on a non-expandable child");
mNaturalHeight = mOldHeight;
}
if (DEBUG) Slog.d(TAG, "got mOldHeight: " + mOldHeight +
" mNaturalHeight: " + mNaturalHeight);
v.getParent().requestDisallowInterceptTouchEvent(true);
}
private void finishScale(boolean force) {
private void finishExpanding(boolean force) {
if (!mExpanding) return;
float currentHeight = mScaler.getHeight();
float targetHeight = mSmallSize;
float h = mScaler.getHeight();
@ -501,6 +535,10 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
mScaleAnimation.start();
}
mCallback.setUserLockedChild(mCurrView, false);
mExpanding = false;
mExpansionStyle = NONE;
if (DEBUG) Slog.d(TAG, "scale was finished on view: " + mCurrView);
}
@ -527,8 +565,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
@Override
public void onClick(View v) {
initScale(v);
finishScale(true);
startExpanding(v, STRETCH);
finishExpanding(true);
clearView();
}