Changed the overscroll and expanding behaviour.

Only the first selected element will be expanded, no subsequent children.
Afterwards, overscrolling is performed.
This improves overscroll consistency a lot and people don't accidentally
expand unwanted notifications, just the one they wanted to.
If the users primary intent is overscrolling (i.e if he drags on a card
which is already expanded), then we allow him to go to the quick settings.

Bug: 14487435
Bug: 15181651
Change-Id: I978cc4e06ae85c2ca69e15a149cb85ac54b2ef35
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 @@
     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 @@
         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 @@
         mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight();
         if (mQsExpanded) {
             if (mQsFullyExpanded) {
-                setQsStackScrollerPadding(mQsMaxExpansionHeight);
+                mQsExpansionHeight = mQsMaxExpansionHeight;
+                requestScrollerTopPaddingUpdate(false /* animate */);
             }
         } else {
             if (!mStackScrollerOverscrolling) {
@@ -202,11 +199,12 @@
      */
     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 @@
                 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 @@
                     mInitialTouchX = x;
                     mQsTracking = true;
                     mIntercepting = false;
+                    mNotificationStackScroller.removeLongPressCallback();
                     return true;
                 }
                 break;
@@ -523,6 +522,13 @@
         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 @@
         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 @@
         mQsExpansionHeight = height;
         mHeader.setExpansion(height - mQsPeekHeight);
         setQsTranslation(height);
-        if (!mStackScrollerOverscrolling) {
-            setQsStackScrollerPadding(height);
-        }
+        requestScrollerTopPaddingUpdate(false /* animate */);
         mStatusBar.userActivity();
     }
 
@@ -579,24 +585,11 @@
         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 @@
     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 @@
 
     @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 @@
     @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 @@
     @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 f43f348..e4133db 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 @@
     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 @@
     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 @@
         overExpansion = Math.max(0, overExpansion);
         if (overExpansion != mOverExpansion) {
             onOverExpansionChanged(overExpansion);
+            mOverExpansion = overExpansion;
         }
 
         if (DEBUG) {
@@ -469,9 +472,7 @@
         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 082fe3a..93b5ee5 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 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 @@
         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 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 @@
         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 @@
         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 @@
     @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 void cancelExpandHelper() {
-        if (mExpandHelper != null) {
-            mExpandHelper.cancel();
+        if (mStackScrollLayout != null) {
+            mStackScrollLayout.cancelExpandHelper();
         }
     }
 }