Implement nice motion for collapsing panel while QS open

Also remove the delay for actions which close the panel. Delaying is
no longer necessary as you still see the touch feedback when the
panel is closed.

Change-Id: I0dffae6998fc41b1590cb182667323f40be3a7d5
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index bac65f8..b71cd77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -241,6 +241,11 @@
      * A listener notifying when {@link #getActualHeight} changes.
      */
     public interface OnHeightChangedListener {
+
+        /**
+         * @param view the view for which the height changed, or {@code null} if just the top
+         *             padding or the padding between the elements changed
+         */
         void onHeightChanged(ExpandableView view);
     }
 }
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 b2e79c9..6334930 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -89,6 +89,7 @@
      */
     private boolean mIntercepting;
     private boolean mQsExpanded;
+    private boolean mQsExpandedWhenExpandingStarted;
     private boolean mQsFullyExpanded;
     private boolean mKeyguardShowing;
     private float mInitialHeightOnTouch;
@@ -112,7 +113,6 @@
 
     private Interpolator mFastOutSlowInInterpolator;
     private Interpolator mFastOutLinearInterpolator;
-    private Interpolator mLinearOutSlowInInterpolator;
     private ObjectAnimator mClockAnimator;
     private int mClockAnimationTarget = -1;
     private int mTopPaddingAdjustment;
@@ -154,8 +154,6 @@
         mNotificationStackScroller.setOverscrollTopChangedListener(this);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
                 android.R.interpolator.fast_out_slow_in);
-        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
-                android.R.interpolator.linear_out_slow_in);
         mFastOutLinearInterpolator = AnimationUtils.loadInterpolator(getContext(),
                 android.R.interpolator.fast_out_linear_in);
         mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
@@ -283,13 +281,6 @@
         requestLayout();
     }
 
-    /**
-     * @return Whether Quick Settings are currently expanded.
-     */
-    public boolean isQsExpanded() {
-        return mQsExpanded;
-    }
-
     public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
         mQsExpansionEnabled = qsExpansionEnabled;
     }
@@ -611,6 +602,7 @@
         if (changed) {
             mQsExpanded = expanded;
             updateQsState();
+            requestPanelHeightUpdate();
         }
     }
 
@@ -794,16 +786,23 @@
 
     @Override
     protected int getMaxPanelHeight() {
+        int min = mStatusBarMinHeight;
         if (mStatusBar.getBarState() != StatusBarState.KEYGUARD
                 && mNotificationStackScroller.getNotGoneChildCount() == 0) {
-            return (int) ((mQsMinExpansionHeight + getOverExpansionAmount())
+            int minHeight = (int) ((mQsMinExpansionHeight + getOverExpansionAmount())
                     * HEADER_RUBBERBAND_FACTOR);
+            min = Math.max(min, minHeight);
         }
-        // TODO: Figure out transition for collapsing when QS is open, adjust height here.
-        int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
-        int maxHeight = mNotificationStackScroller.getHeight() - emptyBottomMargin
-                - mTopPaddingAdjustment;
-        maxHeight = Math.max(maxHeight, mStatusBarMinHeight);
+        int maxHeight;
+        if (mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted) {
+            maxHeight = (int) calculatePanelHeightQsExpanded();
+        } else {
+            int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
+            maxHeight = mNotificationStackScroller.getHeight() - emptyBottomMargin
+                    - mTopPaddingAdjustment;
+            maxHeight += mNotificationStackScroller.getTopPaddingOverflow();
+        }
+        maxHeight = Math.max(maxHeight, min);
         return maxHeight;
     }
 
@@ -816,12 +815,38 @@
         if (!mQsExpanded) {
             positionClockAndNotifications();
         }
+        if (mQsExpanded && !mQsTracking && mQsExpansionAnimator == null
+                && !mQsExpansionFromOverscroll) {
+            float panelHeightQsCollapsed = mNotificationStackScroller.getIntrinsicPadding()
+                    + mNotificationStackScroller.getMinStackHeight()
+                    + mNotificationStackScroller.getNotificationTopPadding();
+            float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
+            float t = (expandedHeight - panelHeightQsCollapsed)
+                    / (panelHeightQsExpanded - panelHeightQsCollapsed);
+            setQsExpansion(mQsMinExpansionHeight
+                    + t * (mQsMaxExpansionHeight - mQsMinExpansionHeight));
+        }
         mNotificationStackScroller.setStackHeight(expandedHeight);
         updateHeader();
         updateUnlockIcon();
         updateNotificationTranslucency();
     }
 
+    private float calculatePanelHeightQsExpanded() {
+        float notificationHeight = mNotificationStackScroller.getHeight()
+                - mNotificationStackScroller.getEmptyBottomMargin()
+                - mNotificationStackScroller.getTopPadding();
+        float totalHeight = mQsMaxExpansionHeight + notificationHeight
+                + mNotificationStackScroller.getNotificationTopPadding();
+        if (totalHeight > mNotificationStackScroller.getHeight()) {
+            float fullyCollapsedHeight = mQsMaxExpansionHeight
+                    + mNotificationStackScroller.getMinStackHeight()
+                    + mNotificationStackScroller.getNotificationTopPadding();
+            totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
+        }
+        return totalHeight;
+    }
+
     private void updateNotificationTranslucency() {
         float alpha = (mNotificationStackScroller.getNotificationsTopY()
                 + mNotificationStackScroller.getItemHeight())
@@ -931,6 +956,7 @@
         super.onExpandingStarted();
         mNotificationStackScroller.onExpansionStarted();
         mIsExpanding = true;
+        mQsExpandedWhenExpandingStarted = mQsExpanded;
     }
 
     @Override
@@ -1005,6 +1031,12 @@
 
     @Override
     public void onHeightChanged(ExpandableView view) {
+
+        // Block update if we are in quick settings and just the top padding changed
+        // (i.e. view == null).
+        if (view == null && mQsExpanded) {
+            return;
+        }
         requestPanelHeightUpdate();
     }
 
@@ -1128,4 +1160,18 @@
             return mQsMinExpansionHeight * HEADER_RUBBERBAND_FACTOR;
         }
     }
+
+    @Override
+    protected float getCannedFlingDurationFactor() {
+        if (mQsExpanded) {
+            return 0.7f;
+        } else {
+            return 0.6f;
+        }
+    }
+
+    @Override
+    protected boolean isTrackingBlocked() {
+        return mConflictingQsExpansionGesture && mQsExpanded;
+    }
 }
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 7d5d99d..2c5ece6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -289,7 +289,7 @@
                     }
                     mJustPeeked = false;
                 }
-                if (!mJustPeeked && (!waitForTouchSlop || mTracking)) {
+                if (!mJustPeeked && (!waitForTouchSlop || mTracking) && !isTrackingBlocked()) {
                     setExpandedHeightInternal(newHeight);
                 }
 
@@ -475,7 +475,8 @@
 
             // Make it shorter if we run a canned animation
             if (vel == 0) {
-                animator.setDuration((long) (animator.getDuration() / 1.75f));
+                animator.setDuration((long)
+                        (animator.getDuration() * getCannedFlingDurationFactor()));
             }
         }
         animator.addListener(new AnimatorListenerAdapter() {
@@ -546,9 +547,12 @@
         float currentMaxPanelHeight = getMaxPanelHeight();
 
         // If the user isn't actively poking us, let's update the height
-        if (!mTracking && mHeightAnimator == null
-                && mExpandedHeight > 0 && currentMaxPanelHeight != mExpandedHeight
-                && !mPeekPending && mPeekAnimator == null) {
+        if ((!mTracking || isTrackingBlocked())
+                && mHeightAnimator == null
+                && mExpandedHeight > 0
+                && currentMaxPanelHeight != mExpandedHeight
+                && !mPeekPending
+                && mPeekAnimator == null) {
             setExpandedHeight(currentMaxPanelHeight);
         }
     }
@@ -576,6 +580,12 @@
         notifyBarPanelExpansionChanged();
     }
 
+    /**
+     * @return true if the panel tracking should be temporarily blocked; this is used when a
+     *         conflicting gesture (opening QS) is happening
+     */
+    protected abstract boolean isTrackingBlocked();
+
     protected abstract void setOverExpansion(float overExpansion, boolean isPixels);
 
     protected abstract void onHeightUpdated(float expandedHeight);
@@ -866,4 +876,6 @@
     public abstract void resetViews();
 
     protected abstract float getPeekHeight();
+
+    protected abstract float getCannedFlingDurationFactor();
 }
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 dbabf31..c4d4655 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1687,9 +1687,6 @@
 
             mStatusBarWindow.cancelExpandHelper();
             mStatusBarView.collapseAllPanels(true);
-            if (isFlippedToSettings()) {
-                flipToNotifications(true /*animate*/);
-            }
         }
     }
 
@@ -1747,18 +1744,10 @@
         }
 
         mNotificationPanel.expand();
-        if (mStackScroller.getVisibility() != View.VISIBLE) {
-            flipToNotifications(true /*animate*/);
-        }
 
         if (false) postStartTracing();
     }
 
-    public void flipToNotifications(boolean animate) {
-        // TODO: Animation
-        mNotificationPanel.closeQs();
-    }
-
     @Override
     public void animateExpandSettingsPanel() {
         if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
@@ -1775,13 +1764,6 @@
         if (false) postStartTracing();
     }
 
-    public boolean isFlippedToSettings() {
-        if (mNotificationPanel != null) {
-            return mNotificationPanel.isQsExpanded();
-        }
-        return false;
-    }
-
     public void animateCollapseQuickSettings() {
         mStatusBarView.collapseAllPanels(true);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 60f38b5..04b1443 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -65,7 +65,6 @@
     private final CurrentUserTracker mUserTracker;
     private final VolumeComponent mVolume;
     private final ArrayList<QSTile<?>> mTiles = new ArrayList<QSTile<?>>();
-    private final int mFeedbackStartDelay;
     private final FlashlightController mFlashlight;
 
     public QSTileHost(Context context, PhoneStatusBar statusBar,
@@ -110,7 +109,6 @@
             }
         };
         mUserTracker.startTracking();
-        mFeedbackStartDelay = mContext.getResources().getInteger(R.integer.feedback_start_delay);
     }
 
     @Override
@@ -120,7 +118,7 @@
 
     @Override
     public void startSettingsActivity(final Intent intent) {
-        mStatusBar.postStartSettingsActivity(intent, mFeedbackStartDelay);
+        mStatusBar.postStartSettingsActivity(intent, 0);
     }
 
     @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 94fdd1f..b46d523 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -150,7 +150,7 @@
     private float mMinTopOverScrollToEscape;
     private int mIntrinsicPadding;
     private int mNotificationTopPadding;
-    private int mMinStackHeight;
+    private float mTopPaddingOverflow;
     private boolean mDontReportNextOverScroll;
 
     /**
@@ -258,7 +258,6 @@
                 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) {
@@ -421,7 +420,7 @@
         int minStackHeight = itemHeight + bottomStackPeekSize;
         int stackHeight;
         if (newStackHeight - mTopPadding >= minStackHeight || getNotGoneChildCount() == 0) {
-            setTranslationY(0);
+            setTranslationY(mTopPaddingOverflow);
             stackHeight = newStackHeight;
         } else {
 
@@ -1195,7 +1194,7 @@
         return view.getHeight();
     }
 
-    private int getContentHeight() {
+    public int getContentHeight() {
         return mContentHeight;
     }
 
@@ -1271,17 +1270,32 @@
     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;
+        int minStackHeight = getMinStackHeight();
+        if (stackHeight <= minStackHeight) {
+            float overflow = minStackHeight - stackHeight;
+            stackHeight = minStackHeight;
             start = getHeight() - stackHeight;
             setTranslationY(overflow);
+            mTopPaddingOverflow = overflow;
         } else {
             setTranslationY(0);
+            mTopPaddingOverflow = 0;
         }
         setTopPadding(clampPadding((int) start), animate);
     }
 
+    public int getNotificationTopPadding() {
+        return mNotificationTopPadding;
+    }
+
+    public int getMinStackHeight() {
+        return mCollapsedSize + mBottomStackPeekSize;
+    }
+
+    public float getTopPaddingOverflow() {
+        return mTopPaddingOverflow;
+    }
+
     public int getPeekHeight() {
         return mIntrinsicPadding + mCollapsedSize + mBottomStackPeekSize;
     }
@@ -1854,6 +1868,10 @@
         mIntrinsicPadding = intrinsicPadding;
     }
 
+    public int getIntrinsicPadding() {
+        return mIntrinsicPadding;
+    }
+
     /**
      * @return the y position of the first notification
      */