Move QS Edit into QSContainer

This will let it play nicely with heads up.

 - Move to QS Container.
 - QS Edit is always full height (some layout hacks to do this)
 - Always draw QS customizer on top when animating
 - Block all panel scrolling while QS edit is open (all touches
   go to editing)
 - Instantaneously change the height of the QS container at
   start/end of animation as needed

Bug: 26969293
Change-Id: Iedc6f5aaf659dcc6750972eae5f69cc0cd2df844
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
index c0c1e4d..5b05e84 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
+import android.graphics.Point;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
@@ -26,7 +27,9 @@
 import android.widget.FrameLayout;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.statusbar.phone.BaseStatusBarHeader;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
@@ -39,6 +42,8 @@
     private static final String TAG = "QSContainer";
     private static final boolean DEBUG = false;
 
+    private final Point mSizePoint = new Point();
+
     private int mHeightOverride = -1;
     private QSPanel mQSPanel;
     private QSDetail mQSDetail;
@@ -51,6 +56,8 @@
 
     private long mDelay;
     private QSAnimator mQSAnimator;
+    private QSCustomizer mQSCustomizer;
+    private NotificationPanelView mPanelView;
 
     public QSContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -65,21 +72,33 @@
         mHeader = (BaseStatusBarHeader) findViewById(R.id.header);
         mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
                 mQSPanel);
+        mQSCustomizer = (QSCustomizer) findViewById(R.id.qs_customize);
+        mQSCustomizer.setQsContainer(this);
     }
 
     public void setHost(QSTileHost qsh) {
-        mQSPanel.setHost(qsh);
+        mQSPanel.setHost(qsh, mQSCustomizer);
         mHeader.setQSPanel(mQSPanel);
         mQSDetail.setHost(qsh);
         mQSAnimator.setHost(qsh);
     }
 
+    public void setPanelView(NotificationPanelView panelView) {
+        mPanelView = panelView;
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // Since we control our own bottom, be whatever size we want.
         // Otherwise the QSPanel ends up with 0 height when the window is only the
         // size of the status bar.
         super.onMeasure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
+
+        // QSCustomizer is always be the height of the screen, but do this after
+        // other measuring to avoid changing the height of the QSContainer.
+        getDisplay().getRealSize(mSizePoint);
+        mQSCustomizer.measure(widthMeasureSpec,
+                MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY));
     }
 
     @Override
@@ -88,6 +107,10 @@
         updateBottom();
     }
 
+    public boolean isCustomizing() {
+        return mQSCustomizer.isCustomizing();
+    }
+
     /**
      * Overrides the height of this view (post-layout), so that the content is clipped to that
      * height and the background is set to that height.
@@ -104,6 +127,9 @@
      * during closing the detail panel, this already returns the smaller height.
      */
     public int getDesiredHeight() {
+        if (isCustomizing()) {
+            return getHeight();
+        }
         if (mQSDetail.isClosingDetail()) {
             return mQSPanel.getGridHeight() + mHeader.getCollapsedHeight() + getPaddingBottom();
         } else {
@@ -111,9 +137,18 @@
         }
     }
 
+    public void notifyCustomizeChanged() {
+        // The customize state changed, so our height changed.
+        updateBottom();
+        // Let the panel know the position changed and it needs to update where notifications
+        // and whatnot are.
+        mPanelView.onQsHeightChanged();
+    }
+
     private void updateBottom() {
         int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
-        int height = (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
+        int height = mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
+                : (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
                 + mHeader.getCollapsedHeight();
         setBottom(getTop() + height);
         mQSDetail.setBottom(getTop() + height);
@@ -138,6 +173,10 @@
         return mQSPanel;
     }
 
+    public QSCustomizer getCustomizer() {
+        return mQSCustomizer;
+    }
+
     public boolean isShowingDetail() {
         return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 71c1913..899b0ef 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -155,12 +155,6 @@
         return mHost.createTile(subPanel);
     }
 
-    protected void createCustomizePanel() {
-        mCustomizePanel = (QSCustomizer) LayoutInflater.from(mContext)
-                .inflate(R.layout.qs_customize_panel, null);
-        mCustomizePanel.setHost(mHost);
-    }
-
     public void setBrightnessMirror(BrightnessMirrorController c) {
         super.onFinishInflate();
         ToggleSlider brightnessSlider = (ToggleSlider) findViewById(R.id.brightness_slider);
@@ -173,12 +167,15 @@
         mCallback = callback;
     }
 
-    public void setHost(QSTileHost host) {
+    public void setHost(QSTileHost host, QSCustomizer customizer) {
         mHost = host;
         mHost.addCallback(this);
         setTiles(mHost.getTiles());
         mFooter.setHost(host);
-        createCustomizePanel();
+        mCustomizePanel = customizer;
+        if (mCustomizePanel != null) {
+            mCustomizePanel.setHost(mHost);
+        }
     }
 
     public QSTileHost getHost() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index f8a57d0..d0e034b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -67,11 +67,6 @@
         TunerService.get(mContext).removeTunable(mNumTiles);
     }
 
-    @Override
-    protected void createCustomizePanel() {
-        // No customizing from the header.
-    }
-
     public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
         mFullPanel = fullPanel;
         mHeader = header;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 5e02428..068efa6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -32,8 +32,10 @@
 import android.widget.Toolbar;
 import android.widget.Toolbar.OnMenuItemClickListener;
 import com.android.systemui.R;
+import com.android.systemui.qs.QSContainer;
 import com.android.systemui.qs.QSDetailClipper;
 import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.QSTileHost;
 
@@ -59,6 +61,9 @@
     private RecyclerView mRecyclerView;
     private TileAdapter mTileAdapter;
     private Toolbar mToolbar;
+    private boolean mCustomizing;
+    private NotificationsQuickSettingsContainer mNotifQsContainer;
+    private QSContainer mQsContainer;
 
     public QSCustomizer(Context context, AttributeSet attrs) {
         super(new ContextThemeWrapper(context, android.R.style.Theme_Material), attrs);
@@ -70,6 +75,14 @@
         mPhoneStatusBar = host.getPhoneStatusBar();
     }
 
+    public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) {
+        mNotifQsContainer = notificationsQsContainer;
+    }
+
+    public void setQsContainer(QSContainer qsContainer) {
+        mQsContainer = qsContainer;
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -105,23 +118,31 @@
     public void show(int x, int y) {
         if (!isShown) {
             isShown = true;
-            mPhoneStatusBar.getStatusBarWindow().addView(this);
             setTileSpecs();
-            mClipper.animateCircularClip(x, y, true, null);
+            setVisibility(View.VISIBLE);
+            mClipper.animateCircularClip(x, y, true, mExpandAnimationListener);
             new TileQueryHelper(mContext, mHost).setListener(mTileAdapter);
+            mNotifQsContainer.setCustomizerAnimating(true);
         }
     }
 
     public void hide(int x, int y) {
         if (isShown) {
             isShown = false;
+            setCustomizing(false);
             save();
             mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
+            mNotifQsContainer.setCustomizerAnimating(true);
         }
     }
 
+    private void setCustomizing(boolean customizing) {
+        mCustomizing = customizing;
+        mQsContainer.notifyCustomizeChanged();
+    }
+
     public boolean isCustomizing() {
-        return isShown;
+        return mCustomizing;
     }
 
     @Override
@@ -155,19 +176,34 @@
         mTileAdapter.saveSpecs(mHost);
     }
 
+    private final AnimatorListener mExpandAnimationListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            setCustomizing(true);
+            mNotifQsContainer.setCustomizerAnimating(false);
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mNotifQsContainer.setCustomizerAnimating(false);
+        }
+    };
+
     private final AnimatorListener mCollapseAnimationListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
             if (!isShown) {
-                mPhoneStatusBar.getStatusBarWindow().removeView(QSCustomizer.this);
+                setVisibility(View.GONE);
             }
+            mNotifQsContainer.setCustomizerAnimating(false);
         }
 
         @Override
         public void onAnimationCancel(Animator animation) {
             if (!isShown) {
-                mPhoneStatusBar.getStatusBarWindow().removeView(QSCustomizer.this);
+                setVisibility(View.GONE);
             }
+            mNotifQsContainer.setCustomizerAnimating(false);
         }
     };
 }
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 88b8afa..9c6f2c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -65,7 +65,7 @@
 import java.util.List;
 
 public class NotificationPanelView extends PanelView implements
-        ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
+        ExpandableView.OnHeightChangedListener,
         View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
         KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
         HeadsUpManager.OnHeadsUpChangedListener {
@@ -222,6 +222,7 @@
             @Override
             public void onInflated(View v) {
                 mQsContainer = (QSContainer) v.findViewById(R.id.quick_settings_container);
+                mQsContainer.setPanelView(NotificationPanelView.this);
                 mQsContainer.getHeader().setOnClickListener(NotificationPanelView.this);
             }
         });
@@ -247,7 +248,7 @@
                 final int height = bottom - top;
                 final int oldHeight = oldBottom - oldTop;
                 if (height != oldHeight) {
-                    onScrollChanged();
+                    onQsHeightChanged();
                 }
             }
         });
@@ -547,7 +548,7 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (mBlockTouches) {
+        if (mBlockTouches || mQsContainer.isCustomizing()) {
             return false;
         }
         initDownStates(event);
@@ -707,7 +708,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        if (mBlockTouches) {
+        if (mBlockTouches || mQsContainer.isCustomizing()) {
             return false;
         }
         initDownStates(event);
@@ -906,18 +907,6 @@
     }
 
     @Override
-    public void onOverscrolled(float lastTouchX, float lastTouchY, int amount) {
-        if (mIntercepting && shouldQuickSettingsIntercept(lastTouchX, lastTouchY,
-                -1 /* yDiff: Not relevant here */)) {
-            mQsTracking = true;
-            onQsExpansionStarted(amount);
-            mInitialHeightOnTouch = mQsExpansionHeight;
-            mInitialTouchY = mLastTouchY;
-            mInitialTouchX = mLastTouchX;
-        }
-    }
-
-    @Override
     public void onOverscrollTopChanged(float amount, boolean isRubberbanded) {
         cancelQsAnimation();
         if (!mQsExpansionEnabled) {
@@ -1719,9 +1708,10 @@
     public void onReset(ExpandableView view) {
     }
 
-    @Override
-    public void onScrollChanged() {
+    public void onQsHeightChanged() {
+        mQsMaxExpansionHeight = mQsContainer.getDesiredHeight();
         if (mQsExpanded) {
+            mQsExpansionHeight = mQsMaxExpansionHeight;
             requestScrollerTopPaddingUpdate(false /* animate */);
             requestPanelHeightUpdate();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 6d90e5c..f0df706 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -24,21 +24,24 @@
 import android.view.ViewStub;
 import android.view.WindowInsets;
 import android.widget.FrameLayout;
-
+import com.android.systemui.DensityContainer;
 import com.android.systemui.R;
+import com.android.systemui.qs.QSContainer;
+import com.android.systemui.qs.customize.QSCustomizer;
 
 /**
  * The container with notification stack scroller and quick settings inside.
  */
 public class NotificationsQuickSettingsContainer extends FrameLayout
-        implements ViewStub.OnInflateListener {
+        implements ViewStub.OnInflateListener, DensityContainer.InflateListener {
 
-    private View mQsContainer;
+    private DensityContainer mQsContainer;
     private View mUserSwitcher;
     private View mStackScroller;
     private View mKeyguardStatusBar;
     private boolean mInflated;
     private boolean mQsExpanded;
+    private boolean mCustomizerAnimating;
 
     public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -47,7 +50,8 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mQsContainer = findViewById(R.id.qs_density_container);
+        mQsContainer = (DensityContainer) findViewById(R.id.qs_density_container);
+        mQsContainer.addInflateListener(this);
         mStackScroller = findViewById(R.id.notification_stack_scroller);
         mKeyguardStatusBar = findViewById(R.id.keyguard_header);
         ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
@@ -80,8 +84,9 @@
         boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE;
         boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
 
-        View stackQsTop = mQsExpanded ? mStackScroller : mQsContainer;
-        View stackQsBottom = !mQsExpanded ? mStackScroller : mQsContainer;
+        final boolean qsBottom = mQsExpanded && !mCustomizerAnimating;
+        View stackQsTop = qsBottom ? mStackScroller : mQsContainer;
+        View stackQsBottom = !qsBottom ? mStackScroller : mQsContainer;
         // Invert the order of the scroll view and user switcher such that the notifications receive
         // touches first but the panel gets drawn above.
         if (child == mQsContainer) {
@@ -117,10 +122,23 @@
         }
     }
 
+    @Override
+    public void onInflated(View v) {
+        QSCustomizer customizer = ((QSContainer) v).getCustomizer();
+        customizer.setContainer(this);
+    }
+
     public void setQsExpanded(boolean expanded) {
         if (mQsExpanded != expanded) {
             mQsExpanded = expanded;
             invalidate();
         }
     }
+
+    public void setCustomizerAnimating(boolean isAnimating) {
+        if (mCustomizerAnimating != isAnimating) {
+            mCustomizerAnimating = isAnimating;
+            invalidate();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 326ca2b..b29c807 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -296,7 +296,7 @@
         mHost = host;
         host.setHeaderView(this);
         mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
-        mHeaderQsPanel.setHost(host);
+        mHeaderQsPanel.setHost(host, null /* No customization in header */);
         setUserInfoController(host.getUserInfoController());
         setBatteryController(host.getBatteryController());
         setNextAlarmController(host.getNextAlarmController());