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> <integer translatable="false" name="config_search_panel_view_vibration_duration">20</integer>
<!-- The length of the vibration when the notificaiotn pops open. --> <!-- 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> </resources>

View File

@@ -152,5 +152,8 @@
<dimen name="carrier_label_height">24dp</dimen> <dimen name="carrier_label_height">24dp</dimen>
<!-- The distance you can pull a notificaiton before it pops open --> <!-- 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> </resources>

View File

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