For Matias.

	<3, dsandler.

Bug: 7348917
Change-Id: I193a94ab82a9e59068c95624c2e8d375543f71f7
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 c832fb8..a857eba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -21,6 +21,8 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.MotionEvent;
 import android.view.View;
 
 import com.android.systemui.R;
@@ -31,11 +33,18 @@
     Drawable mHandleBar;
     float mHandleBarHeight;
     View mHandleView;
+    int mFingers;
+    PhoneStatusBar mStatusBar;
+    private boolean mFlipped;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
+    public void setStatusBar(PhoneStatusBar bar) {
+        mStatusBar = bar;
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -79,4 +88,35 @@
         mHandleBar.draw(canvas);
         canvas.translate(0, -off);
     }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (PhoneStatusBar.SETTINGS_DRAG_SHORTCUT && mStatusBar.mHasFlipSettings) {
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    mFlipped = false;
+                    break;
+                case MotionEvent.ACTION_POINTER_DOWN:
+                    if (!mFlipped) {
+                        float miny = event.getY(0);
+                        float maxy = miny;
+                        for (int i=1; i<event.getPointerCount(); i++) {
+                            final float y = event.getY(i);
+                            if (y < miny) miny = y;
+                            if (y > maxy) maxy = y;
+                        }
+                        if (maxy - miny < mHandleBarHeight) {
+                            if (getMeasuredHeight() < mHandleBarHeight) {
+                                mStatusBar.switchToSettings();
+                            } else {
+                                mStatusBar.flipToSettings();
+                            }
+                            mFlipped = true;
+                        }
+                    }
+                    break;
+            }
+        }
+        return mHandleView.dispatchTouchEvent(event);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index d0fc340..c9a137c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -102,7 +102,7 @@
             startOpeningPanel(panel);
         }
         final boolean result = mTouchingPanel != null
-                ? mTouchingPanel.getHandle().dispatchTouchEvent(event)
+                ? mTouchingPanel.onTouchEvent(event)
                 : true;
         return result;
     }
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 b2bca56..6184e30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -250,6 +250,7 @@
                         case MotionEvent.ACTION_DOWN:
                             mTracking = true;
                             mHandleView.setPressed(true);
+                            postInvalidate(); // catch the press state change
                             mInitialTouchY = y;
                             mVelocityTracker = VelocityTracker.obtain();
                             trackMovement(event);
@@ -283,6 +284,7 @@
                             mFinalTouchY = y;
                             mTracking = false;
                             mHandleView.setPressed(false);
+                            postInvalidate(); // catch the press state change
                             mBar.onTrackingStopped(PanelView.this);
                             trackMovement(event);
 
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 24f76bb..b85062e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -110,6 +110,8 @@
 
     public static final boolean ENABLE_NOTIFICATION_PANEL_CLING = false;
 
+    public static final boolean SETTINGS_DRAG_SHORTCUT = true;
+
     // additional instrumentation for testing purposes; intended to be left on during development
     public static final boolean CHATTY = DEBUG;
 
@@ -180,7 +182,7 @@
     View mMoreIcon;
 
     // expanded notifications
-    PanelView mNotificationPanel; // the sliding/resizing panel within the notification window
+    NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
     ScrollView mScrollView;
     View mExpandedContents;
     int mNotificationPanelGravity;
@@ -363,7 +365,8 @@
         PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
         mStatusBarView.setPanelHolder(holder);
 
-        mNotificationPanel = (PanelView) mStatusBarWindow.findViewById(R.id.notification_panel);
+        mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(R.id.notification_panel);
+        mNotificationPanel.setStatusBar(this);
         mNotificationPanelIsFullScreenWidth =
             (mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT);
 
@@ -1280,6 +1283,10 @@
         }
     }
 
+    public Handler getHandler() {
+        return mHandler;
+    }
+
     View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
         public void onFocusChange(View v, boolean hasFocus) {
             // Because 'v' is a ViewGroup, all its children will be (un)selected
@@ -1294,18 +1301,6 @@
             return;
         }
 
-        if (mHasFlipSettings && !mExpandedVisible) {
-            // reset things to their proper state
-            mScrollView.setScaleX(1f);
-            mScrollView.setVisibility(View.VISIBLE);
-            mSettingsButton.setAlpha(1f);
-            mSettingsButton.setVisibility(View.VISIBLE);
-            mNotificationPanel.setVisibility(View.GONE);
-            mFlipSettingsView.setVisibility(View.GONE);
-            mNotificationButton.setVisibility(View.GONE);
-            setAreThereNotifications(); // show the clear button
-        }
-
         mExpandedVisible = true;
         mPile.setLayoutTransitionsEnabled(true);
         if (mNavigationBarView != null)
@@ -1415,51 +1410,53 @@
         }
 
         mNotificationPanel.expand();
-        if (mHasFlipSettings) {
-            if (mScrollView.getVisibility() != View.VISIBLE) {
-                if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
-                if (mScrollViewAnim != null) mScrollViewAnim.cancel();
-                if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
-                if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
-                if (mClearButtonAnim != null) mClearButtonAnim.cancel();
-
-                mScrollView.setVisibility(View.VISIBLE);
-                mScrollViewAnim = start(
-                    startDelay(FLIP_DURATION_OUT,
-                        interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 0f, 1f)
-                                .setDuration(FLIP_DURATION_IN)
-                            )));
-                mFlipSettingsViewAnim = start(
-                    setVisibilityWhenDone(
-                        interpolator(mAccelerateInterpolator,
-                                ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 1f, 0f)
-                                )
-                            .setDuration(FLIP_DURATION_OUT),
-                        mFlipSettingsView, View.INVISIBLE));
-                mNotificationButtonAnim = start(
-                    setVisibilityWhenDone(
-                        ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
-                            .setDuration(FLIP_DURATION),
-                        mNotificationButton, View.INVISIBLE));
-                mSettingsButton.setVisibility(View.VISIBLE);
-                mSettingsButtonAnim = start(
-                    ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
-                        .setDuration(FLIP_DURATION));
-                mClearButton.setVisibility(View.VISIBLE);
-                mClearButton.setAlpha(0f);
-                setAreThereNotifications(); // this will show/hide the button as necessary
-                mNotificationPanel.postDelayed(new Runnable() {
-                    public void run() {
-                        updateCarrierLabelVisibility(false);
-                    }
-                }, FLIP_DURATION - 150);
-            }
+        if (mHasFlipSettings && mScrollView.getVisibility() != View.VISIBLE) {
+            flipToNotifications();
         }
 
         if (false) postStartTracing();
     }
 
+    public void flipToNotifications() {
+        if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
+        if (mScrollViewAnim != null) mScrollViewAnim.cancel();
+        if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
+        if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
+        if (mClearButtonAnim != null) mClearButtonAnim.cancel();
+
+        mScrollView.setVisibility(View.VISIBLE);
+        mScrollViewAnim = start(
+            startDelay(FLIP_DURATION_OUT,
+                interpolator(mDecelerateInterpolator,
+                    ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 0f, 1f)
+                        .setDuration(FLIP_DURATION_IN)
+                    )));
+        mFlipSettingsViewAnim = start(
+            setVisibilityWhenDone(
+                interpolator(mAccelerateInterpolator,
+                        ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 1f, 0f)
+                        )
+                    .setDuration(FLIP_DURATION_OUT),
+                mFlipSettingsView, View.INVISIBLE));
+        mNotificationButtonAnim = start(
+            setVisibilityWhenDone(
+                ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
+                    .setDuration(FLIP_DURATION),
+                mNotificationButton, View.INVISIBLE));
+        mSettingsButton.setVisibility(View.VISIBLE);
+        mSettingsButtonAnim = start(
+            ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
+                .setDuration(FLIP_DURATION));
+        mClearButton.setVisibility(View.VISIBLE);
+        mClearButton.setAlpha(0f);
+        setAreThereNotifications(); // this will show/hide the button as necessary
+        mNotificationPanel.postDelayed(new Runnable() {
+            public void run() {
+                updateCarrierLabelVisibility(false);
+            }
+        }, FLIP_DURATION - 150);
+    }
+
     @Override
     public void animateExpandSettingsPanel() {
         if (SPEW) Slog.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
@@ -1470,46 +1467,7 @@
         if (mHasFlipSettings) {
             mNotificationPanel.expand();
             if (mFlipSettingsView.getVisibility() != View.VISIBLE) {
-                if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
-                if (mScrollViewAnim != null) mScrollViewAnim.cancel();
-                if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
-                if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
-                if (mClearButtonAnim != null) mClearButtonAnim.cancel();
-
-                mFlipSettingsView.setVisibility(View.VISIBLE);
-                mFlipSettingsView.setScaleX(0f);
-                mFlipSettingsViewAnim = start(
-                    startDelay(FLIP_DURATION_OUT,
-                        interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 0f, 1f)
-                                .setDuration(FLIP_DURATION_IN)
-                            )));
-                mScrollViewAnim = start(
-                    setVisibilityWhenDone(
-                        interpolator(mAccelerateInterpolator,
-                                ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 1f, 0f)
-                                )
-                            .setDuration(FLIP_DURATION_OUT), 
-                        mScrollView, View.INVISIBLE));
-                mSettingsButtonAnim = start(
-                    setVisibilityWhenDone(
-                        ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
-                            .setDuration(FLIP_DURATION),
-                            mScrollView, View.INVISIBLE));
-                mNotificationButton.setVisibility(View.VISIBLE);
-                mNotificationButtonAnim = start(
-                    ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
-                        .setDuration(FLIP_DURATION));
-                mClearButtonAnim = start(
-                    setVisibilityWhenDone(
-                        ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
-                        .setDuration(FLIP_DURATION),
-                        mClearButton, View.INVISIBLE));
-                mNotificationPanel.postDelayed(new Runnable() {
-                    public void run() {
-                        updateCarrierLabelVisibility(false);
-                    }
-                }, FLIP_DURATION - 150);
+                flipToSettings();
             }
         } else if (mSettingsPanel != null) {
             mSettingsPanel.expand();
@@ -1518,6 +1476,69 @@
         if (false) postStartTracing();
     }
 
+    public void switchToSettings() {
+        mFlipSettingsView.setScaleX(1f);
+        mFlipSettingsView.setVisibility(View.VISIBLE);
+        mSettingsButton.setVisibility(View.GONE);
+        mScrollView.setVisibility(View.GONE);
+        mNotificationButton.setVisibility(View.VISIBLE);
+        mNotificationButton.setAlpha(1f);
+        mClearButton.setVisibility(View.GONE);
+    }
+
+    public void flipToSettings() {
+        if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
+        if (mScrollViewAnim != null) mScrollViewAnim.cancel();
+        if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
+        if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
+        if (mClearButtonAnim != null) mClearButtonAnim.cancel();
+
+        mFlipSettingsView.setVisibility(View.VISIBLE);
+        mFlipSettingsView.setScaleX(0f);
+        mFlipSettingsViewAnim = start(
+            startDelay(FLIP_DURATION_OUT,
+                interpolator(mDecelerateInterpolator,
+                    ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 0f, 1f)
+                        .setDuration(FLIP_DURATION_IN)
+                    )));
+        mScrollViewAnim = start(
+            setVisibilityWhenDone(
+                interpolator(mAccelerateInterpolator,
+                        ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 1f, 0f)
+                        )
+                    .setDuration(FLIP_DURATION_OUT), 
+                mScrollView, View.INVISIBLE));
+        mSettingsButtonAnim = start(
+            setVisibilityWhenDone(
+                ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
+                    .setDuration(FLIP_DURATION),
+                    mScrollView, View.INVISIBLE));
+        mNotificationButton.setVisibility(View.VISIBLE);
+        mNotificationButtonAnim = start(
+            ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
+                .setDuration(FLIP_DURATION));
+        mClearButtonAnim = start(
+            setVisibilityWhenDone(
+                ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
+                .setDuration(FLIP_DURATION),
+                mClearButton, View.INVISIBLE));
+        mNotificationPanel.postDelayed(new Runnable() {
+            public void run() {
+                updateCarrierLabelVisibility(false);
+            }
+        }, FLIP_DURATION - 150);
+    }
+
+    public void flipPanels() {
+        if (mHasFlipSettings) {
+            if (mFlipSettingsView.getVisibility() != View.VISIBLE) {
+                flipToSettings();
+            } else {
+                flipToNotifications();
+            }
+        }
+    }
+
     public void animateCollapseQuickSettings() {
         mStatusBarView.collapseAllPanels(true);
     }
@@ -1533,6 +1554,18 @@
         // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
         mStatusBarView.collapseAllPanels(/*animate=*/ false);
 
+        if (mHasFlipSettings) {
+            // reset things to their proper state
+            mScrollView.setScaleX(1f);
+            mScrollView.setVisibility(View.VISIBLE);
+            mSettingsButton.setAlpha(1f);
+            mSettingsButton.setVisibility(View.VISIBLE);
+            mNotificationPanel.setVisibility(View.GONE);
+            mFlipSettingsView.setVisibility(View.GONE);
+            mNotificationButton.setVisibility(View.GONE);
+            setAreThereNotifications(); // show the clear button
+        }
+
         mExpandedVisible = false;
         mPile.setLayoutTransitionsEnabled(false);
         if (mNavigationBarView != null)