Improvements to notification/settings panels:

A) Hide icons corresponding to the active panel with a
   downward push animation. Notes:
   1. this animation will now apply any time the status bar
	  icons are disabled via DISABLE_NOTIFICATION_ICONS.
   2. DISABLE_SYSTEM_INFO will now only hide the right hand
      icons (system status icons, battery, clock). But you
	  weren't using it anyway, right?

B) Stop pulling down the panels in response to just a touch
   on the status bar. (That should never have worked.) In
   general, we now require that a fling proceed more than
   10dp to be treated as a fling with velocity (as opposed
   to a v=0 fling, or "let-go").

C) If a panel is pulled down more than halfway and then let
   go with v=0, it is expanded. If less than halfway, it is
   contracted. (Helps fix B) above, plus it just makes good
   sense.)

Bug: 7211541 (A)
Bug: 7227237 (B)
Bug: 7228541 (B)
Change-Id: I5662269b753376804bf629239835dc212716d5c3
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 6ed5fb7..bf20e9d 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -35,13 +35,13 @@
         android:layout_width="@dimen/status_bar_icon_size"
         android:layout_height="match_parent"
         android:paddingLeft="6dip"
-		android:paddingBottom="2dip"
+        android:paddingBottom="2dip"
         android:src="@drawable/ic_sysbar_lights_out_dot_small"
         android:scaleType="center"
         android:visibility="gone"
         />
 
-    <LinearLayout android:id="@+id/icons"
+    <LinearLayout android:id="@+id/status_bar_contents"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:paddingLeft="6dip"
@@ -50,7 +50,7 @@
         >
 
         <LinearLayout
-			android:id="@+id/notification_icon_area"
+            android:id="@+id/notification_icon_area"
             android:layout_width="0dip"
             android:layout_height="match_parent"
             android:layout_weight="1"
@@ -71,42 +71,48 @@
                 android:orientation="horizontal"/>  
         </LinearLayout>
 
-        <LinearLayout android:id="@+id/statusIcons"
+        <LinearLayout android:id="@+id/system_icon_area"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"/>    
+            android:orientation="horizontal">
 
-        <LinearLayout
-            android:id="@+id/signal_battery_cluster"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:paddingLeft="2dp"
-            android:orientation="horizontal"
-            android:gravity="center"
-            >
-            <include layout="@layout/signal_cluster_view" 
-                android:id="@+id/signal_cluster"
+            <LinearLayout android:id="@+id/statusIcons"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                />
-            <ImageView
-                android:id="@+id/battery"
-                android:layout_height="wrap_content"
+                android:layout_height="match_parent"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"/>    
+    
+            <LinearLayout
+                android:id="@+id/signal_battery_cluster"
                 android:layout_width="wrap_content"
-                android:paddingLeft="4dip"
+                android:layout_height="match_parent"
+                android:paddingLeft="2dp"
+                android:orientation="horizontal"
+                android:gravity="center"
+                >
+                <include layout="@layout/signal_cluster_view" 
+                    android:id="@+id/signal_cluster"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    />
+                <ImageView
+                    android:id="@+id/battery"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:paddingLeft="4dip"
+                    />
+            </LinearLayout>
+    
+            <com.android.systemui.statusbar.policy.Clock
+                android:id="@+id/clock"
+                android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:singleLine="true"
+                android:paddingLeft="6dip"
+                android:gravity="center_vertical|left"
                 />
         </LinearLayout>
-
-        <com.android.systemui.statusbar.policy.Clock
-            android:id="@+id/clock"
-            android:textAppearance="@style/TextAppearance.StatusBar.Clock"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:singleLine="true"
-            android:paddingLeft="6dip"
-            android:gravity="center_vertical|left"
-            />
     </LinearLayout>
         
     <LinearLayout android:id="@+id/ticker"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 13cda3a..90fe558 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -107,6 +107,9 @@
     <!-- Cap on overall resulting fling speed (s^-1) -->
     <dimen name="fling_gesture_max_output_velocity">3000dp</dimen>
 
+    <!-- Minimum distance a fling must travel (anti-jitter) -->
+    <dimen name="fling_gesture_min_dist">10dp</dimen>
+
     <!-- Minimum fraction of the display a gesture must travel, at any velocity, to qualify as a
          collapse request -->
     <item type="dimen" name="collapse_min_display_fraction">10%</item>
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 9a3648f..f623692 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -6,6 +6,7 @@
 import android.util.AttributeSet;
 import android.util.Slog;
 import android.view.MotionEvent;
+import android.view.View;
 import android.widget.FrameLayout;
 
 public class PanelBar extends FrameLayout {
@@ -101,6 +102,7 @@
         PanelView fullyOpenedPanel = null;
         LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
         for (PanelView pv : mPanels) {
+            final boolean visible = pv.getVisibility() == View.VISIBLE;
             // adjust any other panels that may be partially visible
             if (pv.getExpandedHeight() > 0f) {
                 if (mState == STATE_CLOSED) {
@@ -116,6 +118,11 @@
                     pv.setExpandedFraction(1f-frac);
                 }
             }
+            if (pv.getExpandedHeight() > 0f) {
+                if (!visible) pv.setVisibility(View.VISIBLE);
+            } else {
+                if (visible) pv.setVisibility(View.GONE);
+            }
         }
         if (fullyOpenedPanel != null && !mTracking) {
             go(STATE_OPEN);
@@ -138,6 +145,7 @@
             } else {
                 pv.setExpandedFraction(0); // just in case
             }
+            pv.setVisibility(View.GONE);
         }
         if (!waiting) {
             // it's possible that nothing animated, so we replicate the termination 
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 57528a5..45a107d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -37,6 +37,8 @@
     private float mExpandMinDisplayFraction; // classic value: 0.5 (drag open halfway to expand)
     private float mFlingGestureMaxXVelocityPx; // classic value: 150px/s
 
+    private float mFlingGestureMinDistPx;
+
     private float mExpandAccelPx; // classic value: 2000px/s/s
     private float mCollapseAccelPx; // classic value: 2000px/s/s (will be negated to collapse "up")
 
@@ -78,6 +80,8 @@
     private float mVel, mAccel;
     private int mFullHeight = 0;
     private String mViewName;
+    protected float mInitialTouchY;
+    protected float mFinalTouchY;
 
     private void animationTick(long dtms) {
         if (!mTimeAnimator.isStarted()) {
@@ -88,7 +92,14 @@
             mTimeAnimator.start();
             
             mRubberbanding = STRETCH_PAST_CONTENTS && mExpandedHeight > getFullHeight();
-            mClosing = (mExpandedHeight > 0 && mVel < 0) || mRubberbanding;
+            if (mRubberbanding) {
+                mClosing = true;
+            } else if (mVel == 0) {
+                // if the panel is less than halfway open, close it 
+                mClosing = (mFinalTouchY / getFullHeight()) < 0.5f;
+            } else {
+                mClosing = mExpandedHeight > 0 && mVel < 0;
+            }
         } else if (dtms > 0) {
             final float dt = dtms * 0.001f;                  // ms -> s
             LOG("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
@@ -159,6 +170,8 @@
         mFlingExpandMinVelocityPx = res.getDimension(R.dimen.fling_expand_min_velocity);
         mFlingCollapseMinVelocityPx = res.getDimension(R.dimen.fling_collapse_min_velocity);
 
+        mFlingGestureMinDistPx = res.getDimension(R.dimen.fling_gesture_min_dist);
+
         mCollapseMinDisplayFraction = res.getFraction(R.dimen.collapse_min_display_fraction, 1, 1);
         mExpandMinDisplayFraction = res.getFraction(R.dimen.expand_min_display_fraction, 1, 1);
 
@@ -207,6 +220,7 @@
                     switch (event.getAction()) {
                         case MotionEvent.ACTION_DOWN:
                             mTracking = true;
+                            mInitialTouchY = y;
                             mVelocityTracker = VelocityTracker.obtain();
                             trackMovement(event);
                             mBar.onTrackingStarted(PanelView.this);
@@ -223,6 +237,7 @@
 
                         case MotionEvent.ACTION_UP:
                         case MotionEvent.ACTION_CANCEL:
+                            mFinalTouchY = y;
                             mTracking = false;
                             mBar.onTrackingStopped(PanelView.this);
                             trackMovement(event);
@@ -243,11 +258,21 @@
                             if (vel > mFlingGestureMaxOutputVelocityPx) {
                                 vel = mFlingGestureMaxOutputVelocityPx;
                             }
+
+                            // if you've barely moved your finger, we treat the velocity as 0
+                            // preventing spurious flings due to touch screen jitter
+                            final float deltaY = (float)Math.abs(mFinalTouchY - mInitialTouchY);
+                            if (deltaY < mFlingGestureMinDistPx
+                                    || vel < mFlingGestureMinDistPx) {
+                                vel = 0;
+                            }
+
                             if (negative) {
                                 vel = -vel;
                             }
 
-                            LOG("gesture: vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
+                            LOG("gesture: dy=%f vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
+                                    deltaY,
                                     mVelocityTracker.getXVelocity(),
                                     mVelocityTracker.getYVelocity(),
                                     xVel, yVel,
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 7e44b16..2f30a38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -153,11 +153,18 @@
     int mPixelFormat;
     Object mQueueLock = new Object();
 
-    // icons
-    LinearLayout mIcons;
-    IconMerger mNotificationIcons;
-    View mMoreIcon;
+    // viewgroup containing the normal contents of the statusbar
+    LinearLayout mStatusBarContents;
+    
+    // right-hand icons
+    LinearLayout mSystemIconArea;
+    
+    // left-hand icons 
     LinearLayout mStatusIcons;
+    // the icons themselves
+    IconMerger mNotificationIcons;
+    // [+>
+    View mMoreIcon;
 
     // expanded notifications
     PanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -226,8 +233,8 @@
     int[] mAbsPos = new int[2];
     Runnable mPostCollapseCleanup = null;
 
-    private AnimatorSet mLightsOutAnimation;
-    private AnimatorSet mLightsOnAnimation;
+    private Animator mLightsOutAnimation;
+    private Animator mLightsOnAnimation;
 
     // for disabling the status bar
     int mDisabled = 0;
@@ -245,9 +252,9 @@
         @Override
         public void onAnimationEnd(Animator animation) {
             // double-check to avoid races
-            if (mIcons.getAlpha() == 0) {
+            if (mStatusBarContents.getAlpha() == 0) {
                 Slog.d(TAG, "makeIconsInvisible");
-                mIcons.setVisibility(View.INVISIBLE);
+                mStatusBarContents.setVisibility(View.INVISIBLE);
             }
         }
     };
@@ -307,8 +314,7 @@
         mNotificationPanelIsFullScreenWidth =
             (mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT);
         mNotificationPanel.setSystemUiVisibility(
-                  View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER
-                | (mNotificationPanelIsFullScreenWidth ? 0 : View.STATUS_BAR_DISABLE_SYSTEM_INFO));
+                  View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER | View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS);
 
         if (!ActivityManager.isHighEndGfx()) {
             mStatusBarWindow.setBackground(null);
@@ -343,10 +349,12 @@
 
         // figure out which pixel-format to use for the status bar.
         mPixelFormat = PixelFormat.OPAQUE;
+
+        mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area);
         mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons);
         mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
         mNotificationIcons.setOverflowIndicator(mMoreIcon);
-        mIcons = (LinearLayout)mStatusBarView.findViewById(R.id.icons);
+        mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
         mTickerView = mStatusBarView.findViewById(R.id.ticker);
 
         mPile = (NotificationRowLayout)mStatusBarWindow.findViewById(R.id.latestItems);
@@ -431,6 +439,8 @@
         mSettingsPanel.setService(this);
         mSettingsPanel.setup(mNetworkController, mBluetoothController, mBatteryController,
                 mLocationController);
+        mSettingsPanel.setSystemUiVisibility(
+                View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
 
         if (!ActivityManager.isHighEndGfx()) {
             mSettingsPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
@@ -1016,22 +1026,18 @@
         Slog.d(TAG, flagdbg.toString());
 
         if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
-            mIcons.animate().cancel();
+            mSystemIconArea.animate().cancel();
             if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
-                if (mTicking) {
-                    mTicker.halt();
-                }
-                mIcons.animate()
+                mSystemIconArea.animate()
                     .alpha(0f)
                     .translationY(mNaturalBarHeight*0.5f)
-                    //.setStartDelay(100)
                     .setDuration(175)
                     .setInterpolator(new DecelerateInterpolator(1.5f))
                     .setListener(mMakeIconsInvisible)
                     .start();
             } else {
-                mIcons.setVisibility(View.VISIBLE);
-                mIcons.animate()
+                mSystemIconArea.setVisibility(View.VISIBLE);
+                mSystemIconArea.animate()
                     .alpha(1f)
                     .translationY(0)
                     .setStartDelay(0)
@@ -1068,13 +1074,24 @@
             if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
                 if (mTicking) {
                     mTicker.halt();
-                } else {
-                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
                 }
+
+                mNotificationIcons.animate()
+                    .alpha(0f)
+                    .translationY(mNaturalBarHeight*0.5f)
+                    .setDuration(175)
+                    .setInterpolator(new DecelerateInterpolator(1.5f))
+                    .setListener(mMakeIconsInvisible)
+                    .start();
             } else {
-                if (!mExpandedVisible) {
-                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-                }
+                mNotificationIcons.setVisibility(View.VISIBLE);
+                mNotificationIcons.animate()
+                    .alpha(1f)
+                    .translationY(0)
+                    .setStartDelay(0)
+                    .setInterpolator(new DecelerateInterpolator(1.5f))
+                    .setDuration(175)
+                    .start();
             }
         } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
             if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
@@ -1340,30 +1357,11 @@
 
     private void setStatusBarLowProfile(boolean lightsOut) {
         if (mLightsOutAnimation == null) {
-            final View notifications = mStatusBarView.findViewById(R.id.notification_icon_area);
-            final View systemIcons = mStatusBarView.findViewById(R.id.statusIcons);
-            final View signal = mStatusBarView.findViewById(R.id.signal_cluster);
-            final View battery = mStatusBarView.findViewById(R.id.battery);
-            final View clock = mStatusBarView.findViewById(R.id.clock);
-
-            mLightsOutAnimation = new AnimatorSet();
-            mLightsOutAnimation.playTogether(
-                    ObjectAnimator.ofFloat(notifications, View.ALPHA, 0),
-                    ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 0),
-                    ObjectAnimator.ofFloat(signal, View.ALPHA, 0),
-                    ObjectAnimator.ofFloat(battery, View.ALPHA, 0.5f),
-                    ObjectAnimator.ofFloat(clock, View.ALPHA, 0.5f)
-                );
+            mLightsOutAnimation = ObjectAnimator.ofFloat(mStatusBarContents, View.ALPHA, 0);
             mLightsOutAnimation.setDuration(750);
 
             mLightsOnAnimation = new AnimatorSet();
-            mLightsOnAnimation.playTogether(
-                    ObjectAnimator.ofFloat(notifications, View.ALPHA, 1),
-                    ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 1),
-                    ObjectAnimator.ofFloat(signal, View.ALPHA, 1),
-                    ObjectAnimator.ofFloat(battery, View.ALPHA, 1),
-                    ObjectAnimator.ofFloat(clock, View.ALPHA, 1)
-                );
+            mLightsOnAnimation = ObjectAnimator.ofFloat(mStatusBarContents, View.ALPHA, 1);
             mLightsOnAnimation.setDuration(250);
         }
 
@@ -1453,25 +1451,25 @@
         @Override
         public void tickerStarting() {
             mTicking = true;
-            mIcons.setVisibility(View.GONE);
+            mStatusBarContents.setVisibility(View.GONE);
             mTickerView.setVisibility(View.VISIBLE);
             mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
+            mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
         }
 
         @Override
         public void tickerDone() {
-            mIcons.setVisibility(View.VISIBLE);
+            mStatusBarContents.setVisibility(View.VISIBLE);
             mTickerView.setVisibility(View.GONE);
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
+            mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
             mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
                         mTickingDoneListener));
         }
 
         public void tickerHalting() {
-            mIcons.setVisibility(View.VISIBLE);
+            mStatusBarContents.setVisibility(View.VISIBLE);
             mTickerView.setVisibility(View.GONE);
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
+            mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
             mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out,
                         mTickingDoneListener));
         }
@@ -1649,40 +1647,6 @@
                 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
     }
 
-    void performDisableActions(int net) {
-        int old = mDisabled;
-        int diff = net ^ old;
-        mDisabled = net;
-
-        // act accordingly
-        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
-            if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
-                Slog.d(TAG, "DISABLE_EXPAND: yes");
-                animateCollapse();
-            }
-        }
-        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-            if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
-                if (mTicking) {
-                    mNotificationIcons.setVisibility(View.INVISIBLE);
-                    mTicker.halt();
-                } else {
-                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
-                }
-            } else {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
-                if (!mExpandedVisible) {
-                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-                }
-            }
-        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-            if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-                mTicker.halt();
-            }
-        }
-    }
-
     private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
         public void onClick(View v) {
             synchronized (mNotificationData) {