Quick settings improvements

- Remove hole in landscape when no notifications are shown.
- Start intercepting touch events directly when already flinging.
- Fix jump in top panel when collapsing QS in landscape.

Change-Id: If2da5215ee20ea1b0d3a0f88f32c8f5b0dd147da
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 830cd21..1f68cd8 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -86,10 +86,14 @@
                 <!-- A view to reserve space for the collapsed stack -->
                 <!-- Layout height: notification_min_height + bottom_stack_peek_amount -->
                 <View
-                    android:layout_height="76dp"
+                    android:id="@+id/reserve_notification_space"
+                    android:layout_height="@dimen/min_stack_height"
                     android:layout_width="match_parent"
-                    android:layout_marginTop="@dimen/notifications_top_padding"
-                    android:layout_marginBottom="@dimen/notification_side_padding"/>
+                    android:layout_marginTop="@dimen/notifications_top_padding" />
+
+                <View
+                    android:layout_height="@dimen/notification_side_padding"
+                    android:layout_width="match_parent" />
             </LinearLayout>
         </com.android.systemui.statusbar.phone.ObservableScrollView>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index bdbedad..48e633d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -227,6 +227,9 @@
     <!-- Space reserved for the cards behind the top card in the bottom stack -->
     <dimen name="bottom_stack_peek_amount">12dp</dimen>
 
+    <!-- bottom_stack_peek_amount + notification_min_height -->
+    <dimen name="min_stack_height">76dp</dimen>
+
     <!-- The height of the area before the bottom stack in which the notifications slow down -->
     <dimen name="bottom_stack_slow_down_length">12dp</dimen>
 
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 b80a03e..0c6ea50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -66,7 +66,7 @@
     private View mKeyguardStatusView;
     private ObservableScrollView mScrollView;
     private TextView mClockView;
-
+    private View mReserveNotificationSpace;
     private MirrorView mSystemIconsCopy;
 
     private NotificationStackScrollLayout mNotificationStackScroller;
@@ -154,6 +154,7 @@
         mClockView = (TextView) findViewById(R.id.clock_view);
         mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
         mScrollView.setListener(this);
+        mReserveNotificationSpace = findViewById(R.id.reserve_notification_space);
         mNotificationStackScroller = (NotificationStackScrollLayout)
                 findViewById(R.id.notification_stack_scroller);
         mNotificationStackScroller.setOnHeightChangedListener(this);
@@ -357,6 +358,13 @@
                 if (shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, 0)) {
                     getParent().requestDisallowInterceptTouchEvent(true);
                 }
+                if (mQsExpansionAnimator != null) {
+                    onQsExpansionStarted();
+                    mInitialHeightOnTouch = mQsExpansionHeight;
+                    mQsTracking = true;
+                    mIntercepting = false;
+                    mNotificationStackScroller.removeLongPressCallback();
+                }
                 break;
             case MotionEvent.ACTION_POINTER_UP:
                 final int upPointer = event.getPointerId(event.getActionIndex());
@@ -434,8 +442,9 @@
 
     private float getQsExpansionFraction() {
         return (mQsExpansionHeight - mQsMinExpansionHeight)
-                / (mQsMaxExpansionHeight - mQsMinExpansionHeight);
+                / (getTempQsMaxExpansion() - mQsMinExpansionHeight);
     }
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         if (mBlockTouches) {
@@ -541,6 +550,8 @@
                 if ((fraction != 0f || y >= mInitialTouchY)
                         && (fraction != 1f || y <= mInitialTouchY)) {
                     flingQsWithCurrentVelocity();
+                } else {
+                    mScrollYOverride = -1;
                 }
                 if (mVelocityTracker != null) {
                     mVelocityTracker.recycle();
@@ -593,6 +604,9 @@
 
         // Reset scroll position and apply that position to the expanded height.
         float height = mQsExpansionHeight - mScrollView.getScrollY() - overscrollAmount;
+        if (mScrollView.getScrollY() != 0) {
+            mScrollYOverride = mScrollView.getScrollY();
+        }
         mScrollView.scrollTo(0, 0);
         setQsExpansion(height);
     }
@@ -639,7 +653,7 @@
             setQsExpanded(false);
         }
         mQsExpansionHeight = height;
-        mHeader.setExpansion(height - mQsPeekHeight);
+        mHeader.setExpansion(getQsExpansionFraction());
         setQsTranslation(height);
         requestScrollerTopPaddingUpdate(false /* animate */);
         updateNotificationScrim(height);
@@ -698,6 +712,7 @@
     private void flingSettings(float vel, boolean expand, final Runnable onFinishRunnable) {
         float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight;
         if (target == mQsExpansionHeight) {
+            mScrollYOverride = -1;
             if (onFinishRunnable != null) {
                 onFinishRunnable.run();
             }
@@ -714,6 +729,7 @@
         animator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
+                mScrollYOverride = -1;
                 mQsExpansionAnimator = null;
                 if (onFinishRunnable != null) {
                     onFinishRunnable.run();
@@ -827,12 +843,9 @@
             float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
             float t = (expandedHeight - panelHeightQsCollapsed)
                     / (panelHeightQsExpanded - panelHeightQsCollapsed);
-            int qsTempMaxExpansion = mQsMaxExpansionHeight;
-            if (mScrollYOverride != -1) {
-                qsTempMaxExpansion -= mScrollYOverride;
-            }
+
             setQsExpansion(mQsMinExpansionHeight
-                    + t * (qsTempMaxExpansion - mQsMinExpansionHeight));
+                    + t * (getTempQsMaxExpansion() - mQsMinExpansionHeight));
         }
         mNotificationStackScroller.setStackHeight(expandedHeight);
         updateHeader();
@@ -840,6 +853,18 @@
         updateNotificationTranslucency();
     }
 
+    /**
+     * @return a temporary override of {@link #mQsMaxExpansionHeight}, which is needed when
+     *         collapsing QS / the panel when QS was scrolled
+     */
+    private int getTempQsMaxExpansion() {
+        int qsTempMaxExpansion = mQsMaxExpansionHeight;
+        if (mScrollYOverride != -1) {
+            qsTempMaxExpansion -= mScrollYOverride;
+        }
+        return qsTempMaxExpansion;
+    }
+
     private float calculatePanelHeightQsExpanded() {
         float notificationHeight = mNotificationStackScroller.getHeight()
                 - mNotificationStackScroller.getEmptyBottomMargin()
@@ -974,7 +999,6 @@
         mIsExpanding = true;
         mQsExpandedWhenExpandingStarted = mQsExpanded;
         if (mQsExpanded) {
-            mScrollYOverride = mScrollView.getScrollY();
             onQsExpansionStarted();
         }
     }
@@ -1196,4 +1220,12 @@
     protected boolean isTrackingBlocked() {
         return mConflictingQsExpansionGesture && mQsExpanded;
     }
+
+    public void notifyVisibleChildrenChanged() {
+        if (mNotificationStackScroller.getNotGoneChildCount() != 0) {
+            mReserveNotificationSpace.setVisibility(View.VISIBLE);
+        } else {
+            mReserveNotificationSpace.setVisibility(View.GONE);
+        }
+    }
 }
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 3fd3175..43337cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1315,6 +1315,12 @@
         }
     }
 
+    @Override
+    protected void updateRowStates() {
+        super.updateRowStates();
+        mNotificationPanel.notifyVisibleChildrenChanged();
+    }
+
     protected void updateCarrierLabelVisibility(boolean force) {
         // TODO: Handle this for the notification stack scroller as well
         if (!mShowCarrierInPanel) return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 3e2dcef..0aeac1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -300,8 +300,8 @@
         }
     }
 
-    public void setExpansion(float height) {
-        height = (height - mCollapsedHeight) * EXPANSION_RUBBERBAND_FACTOR + mCollapsedHeight;
+    public void setExpansion(float t) {
+        float height = mCollapsedHeight + t * (mExpandedHeight - mCollapsedHeight);
         if (height < mCollapsedHeight) {
             height = mCollapsedHeight;
         }