diff options
10 files changed, 438 insertions, 187 deletions
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 46a66b7..35bc7e3 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -272,6 +272,9 @@ <!-- The padding between the individual notification cards. --> <dimen name="notification_padding">4dp</dimen> + <!-- The minimum amount of top overscroll to go to the quick settings. --> + <dimen name="min_top_overscroll_to_qs">36dp</dimen> + <!-- The height of the collapsed speed bump view. --> <dimen name="speed_bump_height_collapsed">24dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java index 4d6d815..e5e3a1a 100644 --- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java +++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java @@ -42,6 +42,7 @@ public class ExpandHelper implements Gefingerpoken { boolean canChildBeExpanded(View v); void setUserExpandedChild(View v, boolean userExpanded); void setUserLockedChild(View v, boolean userLocked); + void expansionStateChanged(boolean isExpanding); } private static final String TAG = "ExpandHelper"; @@ -77,7 +78,6 @@ public class ExpandHelper implements Gefingerpoken { private boolean mWatchingForPull; private boolean mHasPopped; private View mEventSource; - private View mCurrView; private float mOldHeight; private float mNaturalHeight; private float mInitialTouchFocusY; @@ -86,8 +86,7 @@ public class ExpandHelper implements Gefingerpoken { private float mLastFocusY; private float mLastSpanY; private int mTouchSlop; - private int mLastMotionY; - private float mPopLimit; + private float mLastMotionY; private int mPopDuration; private float mPullGestureMinXSpan; private Callback mCallback; @@ -95,10 +94,14 @@ public class ExpandHelper implements Gefingerpoken { private ViewScaler mScaler; private ObjectAnimator mScaleAnimation; private Vibrator mVibrator; + private boolean mEnabled = true; + private ExpandableView mResizedView; + private float mCurrentHeight; private int mSmallSize; private int mLargeSize; private float mMaximumStretch; + private boolean mOnlyMovements; private int mGravity; @@ -109,17 +112,14 @@ public class ExpandHelper implements Gefingerpoken { @Override public boolean onScaleBegin(ScaleGestureDetector detector) { if (DEBUG_SCALE) Log.v(TAG, "onscalebegin()"); - float focusX = detector.getFocusX(); - float focusY = detector.getFocusY(); - final ExpandableView underFocus = findView(focusX, focusY); - startExpanding(underFocus, STRETCH); + startExpanding(mResizedView, STRETCH); return mExpanding; } @Override public boolean onScale(ScaleGestureDetector detector) { - if (DEBUG_SCALE) Log.v(TAG, "onscale() on " + mCurrView); + if (DEBUG_SCALE) Log.v(TAG, "onscale() on " + mResizedView); return true; } @@ -138,6 +138,7 @@ public class ExpandHelper implements Gefingerpoken { public void setHeight(float h) { if (DEBUG_SCALE) Log.v(TAG, "SetHeight: setting to " + h); mView.setActualHeight((int) h); + mCurrentHeight = h; } public float getHeight() { return mView.getActualHeight(); @@ -165,7 +166,6 @@ public class ExpandHelper implements Gefingerpoken { mGravity = Gravity.TOP; mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f); mScaleAnimation.setDuration(EXPAND_DURATION); - 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); @@ -188,7 +188,6 @@ public class ExpandHelper implements Gefingerpoken { float target = hand + mOldHeight; float newHeight = clamp(target); mScaler.setHeight(newHeight); - mLastFocusY = mSGD.getFocusY(); mLastSpanY = mSGD.getCurrentSpan(); } @@ -252,6 +251,9 @@ public class ExpandHelper implements Gefingerpoken { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { + if (!isEnabled()) { + return false; + } final int action = ev.getAction(); if (DEBUG_SCALE) Log.d(TAG, "intercept: act=" + MotionEvent.actionToString(action) + " expanding=" + mExpanding + @@ -270,38 +272,34 @@ public class ExpandHelper implements Gefingerpoken { if (DEBUG_SCALE) Log.d(TAG, "set initial span: " + mInitialTouchSpan); if (mExpanding) { + mLastMotionY = ev.getRawY(); return true; } else { 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) Log.v(TAG, "got pull gesture (xspan=" + xspan + "px)"); - - final ExpandableView underFocus = findView(x, y); - startExpanding(underFocus, PULL); - return true; - } - if (mScrollAdapter != null && !mScrollAdapter.isScrolledToTop()) { - return false; - } - // Now look for other gestures switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_MOVE: { + final float xspan = mSGD.getCurrentSpanX(); + if (xspan > mPullGestureMinXSpan && + xspan > mSGD.getCurrentSpanY() && !mExpanding) { + // detect a vertical pulling gesture with fingers somewhat separated + if (DEBUG_SCALE) Log.v(TAG, "got pull gesture (xspan=" + xspan + "px)"); + startExpanding(mResizedView, PULL); + mWatchingForPull = false; + } if (mWatchingForPull) { - final int yDiff = y - mLastMotionY; + final float yDiff = ev.getRawY() - mInitialTouchY; if (yDiff > mTouchSlop) { if (DEBUG) Log.v(TAG, "got venetian gesture (dy=" + yDiff + "px)"); - mLastMotionY = y; - final ExpandableView underFocus = findView(x, y); - if (startExpanding(underFocus, BLINDS)) { - mInitialTouchY = mLastMotionY; - mHasPopped = false; + mWatchingForPull = false; + if (mResizedView != null && !isFullyExpanded(mResizedView)) { + if (startExpanding(mResizedView, BLINDS)) { + mLastMotionY = ev.getRawY(); + mInitialTouchY = ev.getRawY(); + mHasPopped = false; + } } } } @@ -310,8 +308,10 @@ public class ExpandHelper implements Gefingerpoken { case MotionEvent.ACTION_DOWN: mWatchingForPull = mScrollAdapter != null && - isInside(mScrollAdapter.getHostView(), x, y); - mLastMotionY = y; + isInside(mScrollAdapter.getHostView(), x, y) + && mScrollAdapter.isScrolledToTop(); + mResizedView = findView(x, y); + mInitialTouchY = ev.getY(); break; case MotionEvent.ACTION_CANCEL: @@ -321,12 +321,28 @@ public class ExpandHelper implements Gefingerpoken { clearView(); break; } + mLastMotionY = ev.getRawY(); return mExpanding; } } + public void setEnabled(boolean enable) { + mEnabled = enable; + } + + private boolean isEnabled() { + return mEnabled; + } + + private boolean isFullyExpanded(ExpandableView underFocus) { + return underFocus.getIntrinsicHeight() == underFocus.getMaxHeight(); + } + @Override public boolean onTouchEvent(MotionEvent ev) { + if (!isEnabled()) { + return false; + } final int action = ev.getActionMasked(); if (DEBUG_SCALE) Log.d(TAG, "touch: act=" + MotionEvent.actionToString(action) + " expanding=" + mExpanding + @@ -335,47 +351,71 @@ public class ExpandHelper implements Gefingerpoken { (0 != (mExpansionStyle & STRETCH) ? " (stretch)" : "")); mSGD.onTouchEvent(ev); + final int x = (int) mSGD.getFocusX(); + final int y = (int) mSGD.getFocusY(); + if (mOnlyMovements) { + mLastMotionY = ev.getRawY(); + return false; + } switch (action) { + case MotionEvent.ACTION_DOWN: + mWatchingForPull = mScrollAdapter != null && + isInside(mScrollAdapter.getHostView(), x, y); + mResizedView = findView(x, y); + mInitialTouchY = ev.getY(); + break; case MotionEvent.ACTION_MOVE: { - if (0 != (mExpansionStyle & BLINDS)) { - final float rawHeight = ev.getY() - mInitialTouchY + mOldHeight; + if (mWatchingForPull) { + final float yDiff = ev.getRawY() - mInitialTouchY; + if (yDiff > mTouchSlop) { + if (DEBUG) Log.v(TAG, "got venetian gesture (dy=" + yDiff + "px)"); + mWatchingForPull = false; + if (mResizedView != null && !isFullyExpanded(mResizedView)) { + if (startExpanding(mResizedView, BLINDS)) { + mInitialTouchY = ev.getRawY(); + mLastMotionY = ev.getRawY(); + mHasPopped = false; + } + } + } + } + if (mExpanding && 0 != (mExpansionStyle & BLINDS)) { + final float rawHeight = ev.getRawY() - mLastMotionY + mCurrentHeight; final float newHeight = clamp(rawHeight); - final boolean wasClosed = (mOldHeight == mSmallSize); boolean isFinished = false; + boolean expanded = false; if (rawHeight > mNaturalHeight) { isFinished = true; + expanded = true; } if (rawHeight < mSmallSize) { isFinished = true; + expanded = false; } - final float pull = Math.abs(ev.getY() - mInitialTouchY); - if (mHasPopped || pull > mPopLimit) { - if (!mHasPopped) { - vibrate(mPopDuration); - mHasPopped = true; - } + if (!mHasPopped) { + vibrate(mPopDuration); + mHasPopped = true; } - if (mHasPopped) { - mScaler.setHeight(newHeight); - } - - final int x = (int) mSGD.getFocusX(); - final int y = (int) mSGD.getFocusY(); - ExpandableView underFocus = findView(x, y); - if (isFinished && underFocus != null && underFocus != mCurrView) { - finishExpanding(false); // @@@ needed? - startExpanding(underFocus, BLINDS); - mInitialTouchY = y; - mHasPopped = false; + mScaler.setHeight(newHeight); + mLastMotionY = ev.getRawY(); + if (isFinished) { + mCallback.setUserExpandedChild(mResizedView, expanded); + mCallback.expansionStateChanged(false); + return false; + } else { + mCallback.expansionStateChanged(true); } return true; } if (mExpanding) { + + // Gestural expansion is running updateExpansion(); + mLastMotionY = ev.getRawY(); return true; } @@ -396,6 +436,7 @@ public class ExpandHelper implements Gefingerpoken { clearView(); break; } + mLastMotionY = ev.getRawY(); return true; } @@ -407,15 +448,16 @@ public class ExpandHelper implements Gefingerpoken { return false; } mExpansionStyle = expandType; - if (mExpanding && v == mCurrView) { + if (mExpanding && v == mResizedView) { return true; } mExpanding = true; + mCallback.expansionStateChanged(true); if (DEBUG) Log.d(TAG, "scale type " + expandType + " beginning on view: " + v); mCallback.setUserLockedChild(v, true); - setView(v); - mScaler.setView((ExpandableView) v); + mScaler.setView(v); mOldHeight = mScaler.getHeight(); + mCurrentHeight = mOldHeight; if (mCallback.canChildBeExpanded(v)) { if (DEBUG) Log.d(TAG, "working on an expandable child"); mNaturalHeight = mScaler.getNaturalHeight(mLargeSize); @@ -425,14 +467,13 @@ public class ExpandHelper implements Gefingerpoken { } if (DEBUG) Log.d(TAG, "got mOldHeight: " + mOldHeight + " mNaturalHeight: " + mNaturalHeight); - v.getParent().requestDisallowInterceptTouchEvent(true); return true; } private void finishExpanding(boolean force) { if (!mExpanding) return; - if (DEBUG) Log.d(TAG, "scale in finishing on view: " + mCurrView); + if (DEBUG) Log.d(TAG, "scale in finishing on view: " + mResizedView); float currentHeight = mScaler.getHeight(); float targetHeight = mSmallSize; @@ -446,11 +487,12 @@ public class ExpandHelper implements Gefingerpoken { if (mScaleAnimation.isRunning()) { mScaleAnimation.cancel(); } - mCallback.setUserExpandedChild(mCurrView, targetHeight == mNaturalHeight); + mCallback.setUserExpandedChild(mResizedView, targetHeight == mNaturalHeight); + mCallback.expansionStateChanged(false); if (targetHeight != currentHeight) { mScaleAnimation.setFloatValues(targetHeight); mScaleAnimation.setupStartValues(); - final View scaledView = mCurrView; + final View scaledView = mResizedView; mScaleAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -460,7 +502,7 @@ public class ExpandHelper implements Gefingerpoken { }); mScaleAnimation.start(); } else { - mCallback.setUserLockedChild(mCurrView, false); + mCallback.setUserLockedChild(mResizedView, false); } mExpanding = false; @@ -470,16 +512,11 @@ public class ExpandHelper implements Gefingerpoken { if (DEBUG) Log.d(TAG, "currentHeight is: " + currentHeight); if (DEBUG) Log.d(TAG, "mSmallSize is: " + mSmallSize); if (DEBUG) Log.d(TAG, "targetHeight is: " + targetHeight); - if (DEBUG) Log.d(TAG, "scale was finished on view: " + mCurrView); + if (DEBUG) Log.d(TAG, "scale was finished on view: " + mResizedView); } private void clearView() { - mCurrView = null; - - } - - private void setView(View v) { - mCurrView = v; + mResizedView = null; } /** @@ -494,6 +531,18 @@ public class ExpandHelper implements Gefingerpoken { } /** + * Change the expansion mode to only observe movements and don't perform any resizing. + * This is needed when the expanding is finished and the scroller kicks in, + * performing an overscroll motion. We only want to shrink it again when we are not + * overscrolled. + * + * @param onlyMovements Should only movements be observed? + */ + public void onlyObserveMovements(boolean onlyMovements) { + mOnlyMovements = onlyMovements; + } + + /** * Triggers haptic feedback. */ private synchronized void vibrate(long duration) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java index 5b2ea0b..517a4e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java @@ -25,7 +25,6 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; - import com.android.systemui.ExpandHelper; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; @@ -87,6 +86,7 @@ public class DragDownHelper implements Gefingerpoken { captureStartingChild(mInitialTouchX, mInitialTouchY); mInitialTouchY = y; mInitialTouchX = x; + mOnDragDownListener.onTouchSlopExceeded(); return true; } break; @@ -202,5 +202,6 @@ public class DragDownHelper implements Gefingerpoken { void onDraggedDown(View startingChild); void onDragDownReset(); void onThresholdReached(); + void onTouchSlopExceeded(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index dbce718..e30117f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -83,10 +83,7 @@ public class NotificationPanelView extends PanelView implements private float mQsExpansionHeight; private int mQsMinExpansionHeight; private int mQsMaxExpansionHeight; - private int mMinStackHeight; private int mQsPeekHeight; - private float mNotificationTranslation; - private int mStackScrollerIntrinsicPadding; private boolean mStackScrollerOverscrolling; private boolean mQsExpansionEnabled = true; private ValueAnimator mQsExpansionAnimator; @@ -165,7 +162,6 @@ public class NotificationPanelView extends PanelView implements super.loadDimens(); mNotificationTopPadding = getResources().getDimensionPixelSize( R.dimen.notifications_top_padding); - mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height); mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f); mStatusBarMinHeight = getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_height); @@ -185,7 +181,8 @@ public class NotificationPanelView extends PanelView implements mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight(); if (mQsExpanded) { if (mQsFullyExpanded) { - setQsStackScrollerPadding(mQsMaxExpansionHeight); + mQsExpansionHeight = mQsMaxExpansionHeight; + requestScrollerTopPaddingUpdate(false /* animate */); } } else { if (!mStackScrollerOverscrolling) { @@ -202,11 +199,12 @@ public class NotificationPanelView extends PanelView implements */ private void positionClockAndNotifications() { boolean animateClock = mNotificationStackScroller.isAddOrRemoveAnimationPending(); + int stackScrollerPadding; if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) { int bottom = mStackScrollerOverscrolling ? mHeader.getCollapsedHeight() : mHeader.getBottom(); - mStackScrollerIntrinsicPadding = bottom + mQsPeekHeight + stackScrollerPadding = bottom + mQsPeekHeight + mNotificationTopPadding; mTopPaddingAdjustment = 0; } else { @@ -224,11 +222,11 @@ public class NotificationPanelView extends PanelView implements mKeyguardStatusView.setY(mClockPositionResult.clockY); } applyClockAlpha(mClockPositionResult.clockAlpha); - mStackScrollerIntrinsicPadding = mClockPositionResult.stackScrollerPadding; + stackScrollerPadding = mClockPositionResult.stackScrollerPadding; mTopPaddingAdjustment = mClockPositionResult.stackScrollerPaddingAdjustment; } - mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding, - mAnimateNextTopPaddingChange || animateClock); + mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding); + requestScrollerTopPaddingUpdate(animateClock); mAnimateNextTopPaddingChange = false; } @@ -384,6 +382,7 @@ public class NotificationPanelView extends PanelView implements mInitialTouchX = x; mQsTracking = true; mIntercepting = false; + mNotificationStackScroller.removeLongPressCallback(); return true; } break; @@ -523,6 +522,13 @@ public class NotificationPanelView extends PanelView implements updateQsState(); } + @Override + public void flingTopOverscroll(float velocity, boolean open) { + mStackScrollerOverscrolling = false; + setQsExpansion(mQsExpansionHeight); + flingSettings(velocity, open); + } + private void onQsExpansionStarted() { onQsExpansionStarted(0); } @@ -554,7 +560,9 @@ public class NotificationPanelView extends PanelView implements mHeader.setExpanded(expandVisually, mStackScrollerOverscrolling); mNotificationStackScroller.setEnabled(!mQsExpanded); mQsPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE); - mQsContainer.setVisibility(mKeyguardShowing && !mQsExpanded ? View.INVISIBLE : View.VISIBLE); + mQsContainer.setVisibility(mKeyguardShowing && !expandVisually + ? View.INVISIBLE + : View.VISIBLE); mScrollView.setTouchEnabled(mQsExpanded); } @@ -569,9 +577,7 @@ public class NotificationPanelView extends PanelView implements mQsExpansionHeight = height; mHeader.setExpansion(height - mQsPeekHeight); setQsTranslation(height); - if (!mStackScrollerOverscrolling) { - setQsStackScrollerPadding(height); - } + requestScrollerTopPaddingUpdate(false /* animate */); mStatusBar.userActivity(); } @@ -579,24 +585,11 @@ public class NotificationPanelView extends PanelView implements mQsContainer.setY(height - mQsContainer.getHeight()); } - private void setQsStackScrollerPadding(float height) { - float start = height - mScrollView.getScrollY() + mNotificationTopPadding; - float stackHeight = mNotificationStackScroller.getHeight() - start; - if (stackHeight <= mMinStackHeight) { - float overflow = mMinStackHeight - stackHeight; - stackHeight = mMinStackHeight; - start = mNotificationStackScroller.getHeight() - stackHeight; - mNotificationStackScroller.setTranslationY(overflow); - mNotificationTranslation = overflow + mScrollView.getScrollY(); - } else { - mNotificationStackScroller.setTranslationY(0); - mNotificationTranslation = mScrollView.getScrollY(); - } - mNotificationStackScroller.setTopPadding(clampQsStackScrollerPadding((int) start), false); - } - private int clampQsStackScrollerPadding(int desiredPadding) { - return Math.max(desiredPadding, mStackScrollerIntrinsicPadding); + private void requestScrollerTopPaddingUpdate(boolean animate) { + mNotificationStackScroller.updateTopPadding(mQsExpansionHeight, + mScrollView.getScrollY(), + mAnimateNextTopPaddingChange || animate); } private void trackMovement(MotionEvent event) { @@ -705,9 +698,11 @@ public class NotificationPanelView extends PanelView implements protected int getMaxPanelHeight() { // TODO: Figure out transition for collapsing when QS is open, adjust height here. int maxPanelHeight = super.getMaxPanelHeight(); - int emptyBottomMargin = mStackScrollerContainer.getHeight() - - mNotificationStackScroller.getHeight() - + mNotificationStackScroller.getEmptyBottomMargin(); + int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin(); + emptyBottomMargin = (int) Math.max(0, + emptyBottomMargin - mNotificationStackScroller.getCurrentOverScrollAmount(true)); + emptyBottomMargin += mStackScrollerContainer.getHeight() + - mNotificationStackScroller.getHeight(); int maxHeight = maxPanelHeight - emptyBottomMargin - mTopPaddingAdjustment; maxHeight = Math.max(maxHeight, mStatusBarMinHeight); return maxHeight; @@ -814,13 +809,14 @@ public class NotificationPanelView extends PanelView implements @Override protected void onOverExpansionChanged(float overExpansion) { - float currentOverScroll = mNotificationStackScroller.getCurrentOverScrolledPixels(true); - float expansionChange = overExpansion - mOverExpansion; - expansionChange *= EXPANSION_RUBBER_BAND_EXTRA_FACTOR; - mNotificationStackScroller.setOverScrolledPixels(currentOverScroll + expansionChange, - true /* onTop */, - false /* animate */); - super.onOverExpansionChanged(overExpansion); + if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) { + float currentOverScroll = mNotificationStackScroller.getCurrentOverScrolledPixels(true); + float expansionChange = overExpansion - mOverExpansion; + expansionChange *= EXPANSION_RUBBER_BAND_EXTRA_FACTOR; + mNotificationStackScroller.setOverScrolledPixels(currentOverScroll + expansionChange, + true /* onTop */, + false /* animate */); + } } @Override @@ -835,7 +831,6 @@ public class NotificationPanelView extends PanelView implements @Override protected void onTrackingStopped(boolean expand) { super.onTrackingStopped(expand); - mOverExpansion = 0.0f; mNotificationStackScroller.setOverScrolledPixels(0.0f, true /* onTop */, true /* animate */); if (expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) { @@ -860,8 +855,7 @@ public class NotificationPanelView extends PanelView implements @Override public void onScrollChanged() { if (mQsExpanded) { - mNotificationStackScroller.setTranslationY( - mNotificationTranslation - mScrollView.getScrollY()); + requestScrollerTopPaddingUpdate(false /* animate */); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 142517c..5442bc9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -53,7 +53,7 @@ public abstract class PanelView extends FrameLayout { private int mEdgeTapAreaWidth; private float mInitialOffsetOnTouch; private float mExpandedFraction = 0; - private float mExpandedHeight = 0; + protected float mExpandedHeight = 0; private boolean mJustPeeked; private boolean mClosing; protected boolean mTracking; @@ -369,8 +369,10 @@ public abstract class PanelView extends FrameLayout { protected void fling(float vel, boolean expand) { cancelPeek(); float target = expand ? getMaxPanelHeight() : 0.0f; - if (target == mExpandedHeight) { + if (target == mExpandedHeight || mOverExpansion > 0) { onExpandingFinished(); + mExpandedHeight = target; + mOverExpansion = 0.0f; mBar.panelExpansionChanged(this, mExpandedFraction); return; } @@ -459,6 +461,7 @@ public abstract class PanelView extends FrameLayout { overExpansion = Math.max(0, overExpansion); if (overExpansion != mOverExpansion) { onOverExpansionChanged(overExpansion); + mOverExpansion = overExpansion; } if (DEBUG) { @@ -469,9 +472,7 @@ public abstract class PanelView extends FrameLayout { mExpandedFraction = Math.min(1f, (fh == 0) ? 0 : mExpandedHeight / fh); } - protected void onOverExpansionChanged(float overExpansion) { - mOverExpansion = overExpansion; - } + protected abstract void onOverExpansionChanged(float overExpansion); protected abstract void onHeightUpdated(float expandedHeight); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 5548bfe..c143148 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -2894,9 +2894,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void updateStackScrollerState() { if (mStackScroller == null) return; - mStackScroller.setDimmed(mState == StatusBarState.KEYGUARD, false /* animate */); - mStackScroller.setVisibility(!mShowLockscreenNotifications && mState == StatusBarState.KEYGUARD + boolean onKeyguard = mState == StatusBarState.KEYGUARD; + mStackScroller.setDimmed(onKeyguard, false /* animate */); + mStackScroller.setVisibility(!mShowLockscreenNotifications && onKeyguard ? View.INVISIBLE : View.VISIBLE); + mStackScroller.setScrollingEnabled(!onKeyguard); + mStackScroller.setExpandingEnabled(!onKeyguard); } public void userActivity() { @@ -3032,6 +3035,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mStackScroller.setDimmed(false /* dimmed */, true /* animate */); } + @Override + public void onTouchSlopExceeded() { + mStackScroller.removeLongPressCallback(); + } + /** * If secure with redaction: Show bouncer, go to unlocked shade. * diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index b51626d..d5e8e8c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -40,7 +40,6 @@ public class StatusBarWindowView extends FrameLayout { public static final String TAG = "StatusBarWindowView"; public static final boolean DEBUG = BaseStatusBar.DEBUG; - private ExpandHelper mExpandHelper; private DragDownHelper mDragDownHelper; private NotificationStackScrollLayout mStackScrollLayout; private NotificationPanelView mNotificationPanel; @@ -73,12 +72,6 @@ public class StatusBarWindowView extends FrameLayout { mStackScrollLayout = (NotificationStackScrollLayout) findViewById( R.id.notification_stack_scroller); mNotificationPanel = (NotificationPanelView) findViewById(R.id.notification_panel); - int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height); - int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height); - mExpandHelper = new ExpandHelper(getContext(), mStackScrollLayout, - minHeight, maxHeight); - mExpandHelper.setEventSource(this); - mExpandHelper.setScrollAdapter(mStackScrollLayout); mDragDownHelper = new DragDownHelper(getContext(), this, mStackScrollLayout, mService); // We really need to be able to animate while window animations are going on @@ -114,12 +107,6 @@ public class StatusBarWindowView extends FrameLayout { boolean intercept = false; if (mNotificationPanel.isFullyExpanded() && mStackScrollLayout.getVisibility() == View.VISIBLE - && (mService.getBarState() == StatusBarState.SHADE - || (mService.getBarState() == StatusBarState.SHADE_LOCKED - && !mService.isBouncerShowing()))) { - intercept = mExpandHelper.onInterceptTouchEvent(ev); - } else if (mNotificationPanel.isFullyExpanded() - && mStackScrollLayout.getVisibility() == View.VISIBLE && mService.getBarState() == StatusBarState.KEYGUARD && !mService.isBouncerShowing()) { intercept = mDragDownHelper.onInterceptTouchEvent(ev); @@ -139,10 +126,7 @@ public class StatusBarWindowView extends FrameLayout { @Override public boolean onTouchEvent(MotionEvent ev) { boolean handled = false; - if (mNotificationPanel.isFullyExpanded() - && mService.getBarState() != StatusBarState.KEYGUARD) { - handled = mExpandHelper.onTouchEvent(ev); - } else if (mService.getBarState() == StatusBarState.KEYGUARD) { + if (mService.getBarState() == StatusBarState.KEYGUARD) { handled = mDragDownHelper.onTouchEvent(ev); } if (!handled) { @@ -168,8 +152,8 @@ public class StatusBarWindowView extends FrameLayout { } public void cancelExpandHelper() { - if (mExpandHelper != null) { - mExpandHelper.cancel(); + if (mStackScrollLayout != null) { + mStackScrollLayout.cancelExpandHelper(); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java index ac26da2..df01c12 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java @@ -225,6 +225,11 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. } } + @Override + public void expansionStateChanged(boolean isExpanding) { + + } + // SwipeHelper.Callback methods @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 5c98d51..bcfe7a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -30,7 +30,6 @@ import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.AnimationUtils; import android.widget.OverScroller; - import com.android.systemui.ExpandHelper; import com.android.systemui.R; import com.android.systemui.SwipeHelper; @@ -51,13 +50,15 @@ public class NotificationStackScrollLayout extends ViewGroup private static final String TAG = "NotificationStackScrollLayout"; private static final boolean DEBUG = false; - private static final float RUBBER_BAND_FACTOR = 0.35f; + private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f; + private static final float RUBBER_BAND_FACTOR_AFTER_EXPAND = 0.15f; /** * Sentinel value for no current active pointer. Used by {@link #mActivePointerId}. */ private static final int INVALID_POINTER = -1; + private ExpandHelper mExpandHelper; private SwipeHelper mSwipeHelper; private boolean mSwipingInProgress; private int mCurrentStackHeight = Integer.MAX_VALUE; @@ -73,6 +74,7 @@ public class NotificationStackScrollLayout extends ViewGroup private float mMaxOverScroll; private boolean mIsBeingDragged; private int mLastMotionY; + private int mDownX; private int mActivePointerId; private int mSidePaddings; @@ -128,6 +130,38 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mChildrenUpdateRequested; private SpeedBumpView mSpeedBumpView; private boolean mIsExpansionChanging; + private boolean mExpandingNotification; + private boolean mExpandedInThisMotion; + private boolean mScrollingEnabled; + + /** + * Was the scroller scrolled to the top when the down motion was observed? + */ + private boolean mScrolledToTopOnFirstDown; + + /** + * The minimal amount of over scroll which is needed in order to switch to the quick settings + * when over scrolling on a expanded card. + */ + private float mMinTopOverScrollToEscape; + private int mIntrinsicPadding; + private int mNotificationTopPadding; + private int mMinStackHeight; + private boolean mDontReportNextOverScroll; + + /** + * The maximum scrollPosition which we are allowed to reach when a notification was expanded. + * This is needed to avoid scrolling too far after the notification was collapsed in the same + * motion. + */ + private int mMaxScrollAfterExpand; + + /** + * Should in this touch motion only be scrolling allowed? It's true when the scroller was + * animating. + */ + private boolean mOnlyScrollingInThisMotion; + private ViewTreeObserver.OnPreDrawListener mChildrenUpdater = new ViewTreeObserver.OnPreDrawListener() { @Override @@ -207,6 +241,17 @@ public class NotificationStackScrollLayout extends ViewGroup mPaddingBetweenElementsNormal = context.getResources() .getDimensionPixelSize(R.dimen.notification_padding); updatePadding(false); + int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height); + int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height); + mExpandHelper = new ExpandHelper(getContext(), this, + minHeight, maxHeight); + mExpandHelper.setEventSource(this); + mExpandHelper.setScrollAdapter(this); + mMinTopOverScrollToEscape = getResources().getDimensionPixelSize( + R.dimen.min_top_overscroll_to_qs); + mNotificationTopPadding = getResources().getDimensionPixelSize( + R.dimen.notifications_top_padding); + mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height); } private void updatePadding(boolean dimmed) { @@ -343,7 +388,7 @@ public class NotificationStackScrollLayout extends ViewGroup return mTopPadding; } - public void setTopPadding(int topPadding, boolean animate) { + private void setTopPadding(int topPadding, boolean animate) { if (mTopPadding != topPadding) { mTopPadding = topPadding; updateAlgorithmHeightAndPadding(); @@ -511,6 +556,29 @@ public class NotificationStackScrollLayout extends ViewGroup if (v instanceof ExpandableNotificationRow) { ((ExpandableNotificationRow) v).setUserLocked(userLocked); } + removeLongPressCallback(); + requestDisallowInterceptTouchEvent(true); + } + + @Override + public void expansionStateChanged(boolean isExpanding) { + mExpandingNotification = isExpanding; + if (!mExpandedInThisMotion) { + mMaxScrollAfterExpand = mOwnScrollY; + mExpandedInThisMotion = true; + } + } + + public void setScrollingEnabled(boolean enable) { + mScrollingEnabled = enable; + } + + public void setExpandingEnabled(boolean enable) { + mExpandHelper.setEnabled(enable); + } + + private boolean isScrollingEnabled() { + return mScrollingEnabled; } public View getChildContentView(View v) { @@ -548,18 +616,44 @@ public class NotificationStackScrollLayout extends ViewGroup if (!isEnabled()) { return false; } + boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL + || ev.getActionMasked()== MotionEvent.ACTION_UP; + boolean expandWantsIt = false; + if (!mSwipingInProgress && !mOnlyScrollingInThisMotion) { + if (isCancelOrUp) { + mExpandHelper.onlyObserveMovements(false); + } + boolean wasExpandingBefore = mExpandingNotification; + expandWantsIt = mExpandHelper.onTouchEvent(ev); + if (mExpandedInThisMotion && !mExpandingNotification && wasExpandingBefore) { + dispatchDownEventToScroller(ev); + } + } boolean scrollerWantsIt = false; - if (!mSwipingInProgress) { + if (!mSwipingInProgress && !mExpandingNotification) { scrollerWantsIt = onScrollTouch(ev); } boolean horizontalSwipeWantsIt = false; - if (!mIsBeingDragged) { + if (!mIsBeingDragged + && !mExpandingNotification + && !mExpandedInThisMotion + && !mOnlyScrollingInThisMotion) { horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev); } - return horizontalSwipeWantsIt || scrollerWantsIt || super.onTouchEvent(ev); + return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev); + } + + private void dispatchDownEventToScroller(MotionEvent ev) { + MotionEvent downEvent = MotionEvent.obtain(ev); + downEvent.setAction(MotionEvent.ACTION_DOWN); + onScrollTouch(downEvent); + downEvent.recycle(); } private boolean onScrollTouch(MotionEvent ev) { + if (!isScrollingEnabled()) { + return false; + } initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(ev); @@ -583,6 +677,7 @@ public class NotificationStackScrollLayout extends ViewGroup // Remember where the motion event started mLastMotionY = (int) ev.getY(); + mDownX = (int) ev.getX(); mActivePointerId = ev.getPointerId(0); break; } @@ -594,8 +689,11 @@ public class NotificationStackScrollLayout extends ViewGroup } final int y = (int) ev.getY(activePointerIndex); + final int x = (int) ev.getX(activePointerIndex); int deltaY = mLastMotionY - y; - if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) { + final int xDiff = Math.abs(x - mDownX); + final int yDiff = Math.abs(deltaY); + if (!mIsBeingDragged && yDiff > mTouchSlop && yDiff > xDiff) { setIsBeingDragged(true); if (deltaY > 0) { deltaY -= mTouchSlop; @@ -606,7 +704,10 @@ public class NotificationStackScrollLayout extends ViewGroup if (mIsBeingDragged) { // Scroll to follow the motion event mLastMotionY = y; - final int range = getScrollRange(); + int range = getScrollRange(); + if (mExpandedInThisMotion) { + range = Math.min(range, mMaxScrollAfterExpand); + } float scrollAmount; if (deltaY < 0) { @@ -631,19 +732,28 @@ public class NotificationStackScrollLayout extends ViewGroup velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId); - if (getChildCount() > 0) { - if ((Math.abs(initialVelocity) > mMinimumVelocity)) { - fling(-initialVelocity); - } else { - if (mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0, - getScrollRange())) { - postInvalidateOnAnimation(); + if (shouldOverScrollFling(initialVelocity)) { + onOverScrollFling(true, initialVelocity); + } else { + if (getChildCount() > 0) { + if ((Math.abs(initialVelocity) > mMinimumVelocity)) { + float currentOverScrollTop = getCurrentOverScrollAmount(true); + if (currentOverScrollTop == 0.0f || initialVelocity > 0) { + fling(-initialVelocity); + } else { + onOverScrollFling(false, initialVelocity); + } + } else { + if (mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0, + getScrollRange())) { + postInvalidateOnAnimation(); + } } } - } - mActivePointerId = INVALID_POINTER; - endDrag(); + mActivePointerId = INVALID_POINTER; + endDrag(); + } } break; case MotionEvent.ACTION_CANCEL: @@ -658,17 +768,27 @@ public class NotificationStackScrollLayout extends ViewGroup case MotionEvent.ACTION_POINTER_DOWN: { final int index = ev.getActionIndex(); mLastMotionY = (int) ev.getY(index); + mDownX = (int) ev.getX(index); mActivePointerId = ev.getPointerId(index); break; } case MotionEvent.ACTION_POINTER_UP: onSecondaryPointerUp(ev); mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId)); + mDownX = (int) ev.getX(ev.findPointerIndex(mActivePointerId)); break; } return true; } + private void onOverScrollFling(boolean open, int initialVelocity) { + if (mOverscrollTopChangedListener != null) { + mOverscrollTopChangedListener.flingTopOverscroll(initialVelocity, open); + } + mDontReportNextOverScroll = true; + setOverScrollAmount(0.0f, true, false); + } + /** * Perform a scroll upwards and adapt the overscroll amounts accordingly * @@ -689,11 +809,13 @@ public class NotificationStackScrollLayout extends ViewGroup float scrollAmount = newTopAmount < 0 ? -newTopAmount : 0.0f; float newScrollY = mOwnScrollY + scrollAmount; if (newScrollY > range) { - float currentBottomPixels = getCurrentOverScrolledPixels(false); - // We overScroll on the top - setOverScrolledPixels(currentBottomPixels + newScrollY - range, - false /* onTop */, - false /* animate */); + if (!mExpandedInThisMotion) { + float currentBottomPixels = getCurrentOverScrolledPixels(false); + // We overScroll on the top + setOverScrolledPixels(currentBottomPixels + newScrollY - range, + false /* onTop */, + false /* animate */); + } mOwnScrollY = range; scrollAmount = 0.0f; } @@ -834,7 +956,7 @@ public class NotificationStackScrollLayout extends ViewGroup * @param animate Should an animation be performed. */ public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) { - setOverScrollAmount(numPixels * RUBBER_BAND_FACTOR, onTop, animate, true); + setOverScrollAmount(numPixels * getRubberBandFactor(), onTop, animate, true); } /** @@ -870,17 +992,21 @@ public class NotificationStackScrollLayout extends ViewGroup if (animate) { mStateAnimator.animateOverScrollToAmount(amount, onTop); } else { - setOverScrolledPixels(amount / RUBBER_BAND_FACTOR, onTop); + setOverScrolledPixels(amount / getRubberBandFactor(), onTop); mAmbientState.setOverScrollAmount(amount, onTop); - requestChildrenUpdate(); if (onTop) { - float scrollAmount = mOwnScrollY < 0 ? -mOwnScrollY : 0; - notifyOverscrollTopListener(scrollAmount + amount); + notifyOverscrollTopListener(amount); } + requestChildrenUpdate(); } } private void notifyOverscrollTopListener(float amount) { + mExpandHelper.onlyObserveMovements(amount > 1.0f); + if (mDontReportNextOverScroll) { + mDontReportNextOverScroll = false; + return; + } if (mOverscrollTopChangedListener != null) { mOverscrollTopChangedListener.onOverscrollTopChanged(amount); } @@ -928,7 +1054,7 @@ public class NotificationStackScrollLayout extends ViewGroup updateChildren(); float overScrollTop = getCurrentOverScrollAmount(true); if (mOwnScrollY < 0) { - notifyOverscrollTopListener(-mOwnScrollY + overScrollTop); + notifyOverscrollTopListener(-mOwnScrollY); } else { notifyOverscrollTopListener(overScrollTop); } @@ -950,6 +1076,7 @@ public class NotificationStackScrollLayout extends ViewGroup onTop = true; newAmount = -mOwnScrollY; mOwnScrollY = 0; + mDontReportNextOverScroll = true; } else { onTop = false; newAmount = mOwnScrollY - scrollRange; @@ -1085,13 +1212,14 @@ public class NotificationStackScrollLayout extends ViewGroup float bottomAmount = getCurrentOverScrollAmount(false); if (velocityY < 0 && topAmount > 0) { mOwnScrollY -= (int) topAmount; + mDontReportNextOverScroll = true; setOverScrollAmount(0, true, false); - mMaxOverScroll = Math.abs(velocityY) / 1000f * RUBBER_BAND_FACTOR + mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor() * mOverflingDistance + topAmount; } else if (velocityY > 0 && bottomAmount > 0) { mOwnScrollY += bottomAmount; setOverScrollAmount(0, false, false); - mMaxOverScroll = Math.abs(velocityY) / 1000f * RUBBER_BAND_FACTOR + mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor() * mOverflingDistance + bottomAmount; } else { // it will be set once we reach the boundary @@ -1104,6 +1232,44 @@ public class NotificationStackScrollLayout extends ViewGroup } } + /** + * @return Whether a fling performed on the top overscroll edge lead to the expanded + * overScroll view (i.e QS). + */ + private boolean shouldOverScrollFling(int initialVelocity) { + float topOverScroll = getCurrentOverScrollAmount(true); + return mScrolledToTopOnFirstDown + && !mExpandedInThisMotion + && topOverScroll > mMinTopOverScrollToEscape + && initialVelocity > 0; + } + + public void updateTopPadding(float qsHeight, int scrollY, boolean animate) { + float start = qsHeight - scrollY + mNotificationTopPadding; + float stackHeight = getHeight() - start; + if (stackHeight <= mMinStackHeight) { + float overflow = mMinStackHeight - stackHeight; + stackHeight = mMinStackHeight; + start = getHeight() - stackHeight; + setTranslationY(overflow); + } else { + setTranslationY(0); + } + setTopPadding(clampPadding((int) start), animate); + } + + private int clampPadding(int desiredPadding) { + return Math.max(desiredPadding, mIntrinsicPadding); + } + + private float getRubberBandFactor() { + return mExpandedInThisMotion + ? RUBBER_BAND_FACTOR_AFTER_EXPAND + : (mScrolledToTopOnFirstDown + ? 1.0f + : RUBBER_BAND_FACTOR_NORMAL); + } + private void endDrag() { setIsBeingDragged(false); @@ -1119,16 +1285,30 @@ public class NotificationStackScrollLayout extends ViewGroup @Override public boolean onInterceptTouchEvent(MotionEvent ev) { + initDownStates(ev); + boolean expandWantsIt = false; + if (!mSwipingInProgress && !mOnlyScrollingInThisMotion) { + expandWantsIt = mExpandHelper.onInterceptTouchEvent(ev); + } boolean scrollWantsIt = false; - if (!mSwipingInProgress) { + if (!mSwipingInProgress && !mExpandingNotification) { scrollWantsIt = onInterceptTouchEventScroll(ev); } boolean swipeWantsIt = false; - if (!mIsBeingDragged) { + if (!mIsBeingDragged + && !mExpandingNotification + && !mExpandedInThisMotion + && !mOnlyScrollingInThisMotion) { swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev); } - return swipeWantsIt || scrollWantsIt || - super.onInterceptTouchEvent(ev); + return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev); + } + + private void initDownStates(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mExpandedInThisMotion = false; + mOnlyScrollingInThisMotion = !mScroller.isFinished(); + } } @Override @@ -1350,6 +1530,9 @@ public class NotificationStackScrollLayout extends ViewGroup } private boolean onInterceptTouchEventScroll(MotionEvent ev) { + if (!isScrollingEnabled()) { + return false; + } /* * This method JUST determines whether we want to intercept the motion. * If we return true, onMotionEvent will be called and we do the actual @@ -1366,13 +1549,6 @@ public class NotificationStackScrollLayout extends ViewGroup return true; } - /* - * Don't try to intercept touch if we can't scroll anyway. - */ - if (mOwnScrollY == 0 && getScrollRange() == 0) { - return false; - } - switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_MOVE: { /* @@ -1398,10 +1574,13 @@ public class NotificationStackScrollLayout extends ViewGroup } final int y = (int) ev.getY(pointerIndex); + final int x = (int) ev.getX(pointerIndex); final int yDiff = Math.abs(y - mLastMotionY); - if (yDiff > mTouchSlop) { + final int xDiff = Math.abs(x - mDownX); + if (yDiff > mTouchSlop && yDiff > xDiff) { setIsBeingDragged(true); mLastMotionY = y; + mDownX = x; initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(ev); } @@ -1421,7 +1600,9 @@ public class NotificationStackScrollLayout extends ViewGroup * ACTION_DOWN always refers to pointer index 0. */ mLastMotionY = y; + mDownX = (int) ev.getX(); mActivePointerId = ev.getPointerId(0); + mScrolledToTopOnFirstDown = isScrolledToTop(); initOrResetVelocityTracker(); mVelocityTracker.addMovement(ev); @@ -1468,7 +1649,7 @@ public class NotificationStackScrollLayout extends ViewGroup mIsBeingDragged = isDragged; if (isDragged) { requestDisallowInterceptTouchEvent(true); - mSwipeHelper.removeLongPressCallback(); + removeLongPressCallback(); } } @@ -1476,10 +1657,14 @@ public class NotificationStackScrollLayout extends ViewGroup public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); if (!hasWindowFocus) { - mSwipeHelper.removeLongPressCallback(); + removeLongPressCallback(); } } + public void removeLongPressCallback() { + mSwipeHelper.removeLongPressCallback(); + } + @Override public boolean isScrolledToTop() { return mOwnScrollY == 0; @@ -1608,6 +1793,14 @@ public class NotificationStackScrollLayout extends ViewGroup updateSpeedBump(true); } + public void cancelExpandHelper() { + mExpandHelper.cancel(); + } + + public void setIntrinsicPadding(int intrinsicPadding) { + mIntrinsicPadding = intrinsicPadding; + } + /** * @return the y position of the first notification */ @@ -1627,6 +1820,15 @@ public class NotificationStackScrollLayout extends ViewGroup */ public interface OnOverscrollTopChangedListener { public void onOverscrollTopChanged(float amount); + + /** + * Notify a listener that the scroller wants to escape from the scrolling motion and + * start a fling animation to the expanded or collapsed overscroll view (e.g expand the QS) + * + * @param velocity The velocity that the Scroller had when over flinging + * @param open Should the fling open or close the overscroll view. + */ + public void flingTopOverscroll(float velocity, boolean open); } static class AnimationEvent { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index 2b52c7e..a48cab8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -131,10 +131,14 @@ public class StackScrollAlgorithm { algorithmState.scrolledPixelsTop = 0; algorithmState.itemsInBottomStack = 0.0f; algorithmState.partialInBottom = 0.0f; - float topOverScroll = ambientState.getOverScrollAmount(true /* onTop */); float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */); - algorithmState.scrollY = (int) (ambientState.getScrollY() + mCollapsedSize - + bottomOverScroll - topOverScroll); + + int scrollY = ambientState.getScrollY(); + + // Due to the overScroller, the stackscroller can have negative scroll state. This is + // already accounted for by the top padding and doesn't need an additional adaption + scrollY = Math.max(0, scrollY); + algorithmState.scrollY = (int) (scrollY + mCollapsedSize + bottomOverScroll); updateVisibleChildren(resultState, algorithmState); |