OSDN Git Service

Improve transient bar transitions.
authorJohn Spurlock <jspurlock@google.com>
Tue, 20 Aug 2013 19:13:47 +0000 (15:13 -0400)
committerJohn Spurlock <jspurlock@google.com>
Tue, 20 Aug 2013 19:37:03 +0000 (15:37 -0400)
1. If app clears transient flag w/ a gesture, the touch-outside
listener would always win, causing an unsightly hide + immediate
reshow.  Instead, give the app some time to clear the flag, then
perform a smooth transition in place.

2. When the transient bars are hidden, we do not know ahead of time
which background will be used on reshow (if transient bars are
revealed, the background is semi-transparent, if transient bars
are cleared, the background is opaque).  Window manager is responsible
for showing windows, but sysui is responsible for setting the view
background.  Therefore, we need some level of coordination between
the two in this case.  Introduce two new non-public sysui flags
that represent the window manager's request to reshow the hidden
bars, but do not reshow until sysui acknowledges (by clearing the flag).
This gives sysui whatever time is necessary to prepare itself for
reshow, avoiding unsightly blip from opaque -> transparent during
the enter animation.

3. When both system bars are hidden, any low-profile changes are
moot.  Avoid unsightly low-profile animations during bar reshow
by suppressing the flag in this case.

4. Improve transient bar home -> launcher transition by cancelling
the -> opaque animation.  This also fixes a bug where hitting
home from the transient bar would leave you with a semi-transparent
bar in a non-transient state.

Bug:10284800
Change-Id: I238210561d8d5f70c1a517283b986c9105a1ec75

core/java/android/app/StatusBarManager.java
core/java/android/view/View.java
packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
policy/src/com/android/internal/policy/impl/BarController.java
policy/src/com/android/internal/policy/impl/PhoneWindowManager.java

index 1acac85..7bcf43e 100644 (file)
@@ -66,8 +66,9 @@ public class StatusBarManager {
     public static final int WINDOW_STATUS_BAR = 1;
     public static final int WINDOW_NAVIGATION_BAR = 2;
 
+    public static final int WINDOW_STATE_SHOWING = 0;
     public static final int WINDOW_STATE_HIDING = 1;
-    public static final int WINDOW_STATE_SHOWING = 2;
+    public static final int WINDOW_STATE_HIDDEN = 2;
 
     private Context mContext;
     private IStatusBarService mService;
@@ -185,4 +186,12 @@ public class StatusBarManager {
             throw new RuntimeException(ex);
         }
     }
+
+    /** @hide */
+    public static String windowStateToString(int state) {
+        if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
+        if (state == WINDOW_STATE_HIDDEN) return "WINDOW_STATE_HIDDEN";
+        if (state == WINDOW_STATE_SHOWING) return "WINDOW_STATE_SHOWING";
+        return "WINDOW_STATE_UNKNOWN";
+    }
 }
index f05e372..5269ee3 100644 (file)
@@ -2542,6 +2542,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
 
     /**
      * @hide
+     *
+     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+     * out of the public fields to keep the undefined bits out of the developer's way.
+     *
+     * Flag to specify that the hidden status bar would like to be shown.
+     */
+    public static final int STATUS_BAR_UNHIDE = 0x10000000;
+
+    /**
+     * @hide
+     *
+     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+     * out of the public fields to keep the undefined bits out of the developer's way.
+     *
+     * Flag to specify that the hidden navigation bar would like to be shown.
+     */
+    public static final int NAVIGATION_BAR_UNHIDE = 0x20000000;
+
+    /**
+     * @hide
      */
     public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x0000FFFF;
 
index 53041b7..e8173b7 100644 (file)
@@ -236,7 +236,7 @@ public class CommandQueue extends IStatusBar.Stub {
 
     public void setWindowState(int window, int state) {
         synchronized (mList) {
-            mHandler.removeMessages(MSG_SET_WINDOW_STATE);
+            // don't coalesce these
             mHandler.obtainMessage(MSG_SET_WINDOW_STATE, window, state, null).sendToTarget();
         }
     }
index e40c4e5..292ea7c 100644 (file)
@@ -37,12 +37,13 @@ public class BarTransitions {
     public static final int MODE_TRANSPARENT = 2;
 
     private final String mTag;
-    private final View mTarget;
-    private final int mOpaque;
-    private final int mSemiTransparent;
+    protected final View mTarget;
+    protected final int mOpaque;
+    protected final int mSemiTransparent;
 
     protected Drawable mTransparent;
     private int mMode;
+    private ValueAnimator mBackgroundColorAnimator;
 
     private final AnimatorUpdateListener mBackgroundColorListener = new AnimatorUpdateListener() {
         @Override
@@ -80,10 +81,11 @@ public class BarTransitions {
     }
 
     protected void onTransition(int oldMode, int newMode, boolean animate) {
+        cancelBackgroundColorAnimation();
         if (animate && oldMode == MODE_SEMI_TRANSPARENT && newMode == MODE_OPAQUE) {
-            startColorAnimation(mSemiTransparent, mOpaque);
+            startBackgroundColorAnimation(mSemiTransparent, mOpaque);
         } else if (animate && oldMode == MODE_OPAQUE && newMode == MODE_SEMI_TRANSPARENT) {
-            startColorAnimation(mOpaque, mSemiTransparent);
+            startBackgroundColorAnimation(mOpaque, mSemiTransparent);
         } else if (newMode == MODE_OPAQUE || newMode == MODE_SEMI_TRANSPARENT) {
             mTarget.setBackgroundColor(newMode == MODE_OPAQUE ? mOpaque : mSemiTransparent);
         } else {
@@ -93,10 +95,17 @@ public class BarTransitions {
         }
     }
 
-    private void startColorAnimation(int from, int to) {
-        ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluator(), from, to);
-        anim.addUpdateListener(mBackgroundColorListener);
-        anim.start();
+    private void startBackgroundColorAnimation(int from, int to) {
+        mBackgroundColorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), from, to);
+        mBackgroundColorAnimator.addUpdateListener(mBackgroundColorListener);
+        mBackgroundColorAnimator.start();
+    }
+
+    private void cancelBackgroundColorAnimation() {
+        if (mBackgroundColorAnimator != null && mBackgroundColorAnimator.isStarted()) {
+            mBackgroundColorAnimator.cancel();
+            mBackgroundColorAnimator = null;
+        }
     }
 
     public static String modeToString(int mode) {
index ad53fea..b36bedd 100644 (file)
@@ -1841,37 +1841,26 @@ public class PhoneStatusBar extends BaseStatusBar {
 
     @Override // CommandQueue
     public void setWindowState(int window, int state) {
+        boolean showing = state == StatusBarManager.WINDOW_STATE_SHOWING;
         if (mStatusBarWindow != null
                 && window == StatusBarManager.WINDOW_STATUS_BAR
                 && mStatusBarWindowState != state) {
             mStatusBarWindowState = state;
-            if (DEBUG) Log.d(TAG, "Status bar window " + stateString(state));
-            if (state == StatusBarManager.WINDOW_STATE_HIDING) {
-                mStatusBarWindow.setEnabled(false);
+            if (DEBUG) Log.d(TAG, "Status bar " + StatusBarManager.windowStateToString(state));
+            mStatusBarWindow.setEnabled(showing);
+            if (!showing) {
                 mStatusBarView.collapseAllPanels(false);
-            } else if (state == StatusBarManager.WINDOW_STATE_SHOWING) {
-                mStatusBarWindow.setEnabled(true);
             }
         }
         if (mNavigationBarView != null
                 && window == StatusBarManager.WINDOW_NAVIGATION_BAR
                 && mNavigationBarWindowState != state) {
             mNavigationBarWindowState = state;
-            if (DEBUG) Log.d(TAG, "Navigation bar window " + stateString(state));
-            if (state == StatusBarManager.WINDOW_STATE_HIDING) {
-                mNavigationBarView.setEnabled(false);
-            } else if (state == StatusBarManager.WINDOW_STATE_SHOWING) {
-                mNavigationBarView.setEnabled(true);
-            }
+            if (DEBUG) Log.d(TAG, "Navigation bar " + StatusBarManager.windowStateToString(state));
+            mNavigationBarView.setEnabled(showing);
         }
     }
 
-    private static String stateString(int state) {
-        if (state == StatusBarManager.WINDOW_STATE_HIDING) return "hiding";
-        if (state == StatusBarManager.WINDOW_STATE_SHOWING) return "showing";
-        return "unknown";
-    }
-
     @Override // CommandQueue
     public void setSystemUiVisibility(int vis, int mask) {
         final int oldVal = mSystemUiVisibility;
@@ -1904,11 +1893,13 @@ public class PhoneStatusBar extends BaseStatusBar {
 
             // update status bar mode
             int sbMode = updateBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(),
-                    View.STATUS_BAR_TRANSIENT, View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS);
+                    View.STATUS_BAR_TRANSIENT, View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS,
+                    mStatusBarWindowState);
 
             // update navigation bar mode
             int nbMode = updateBarMode(oldVal, newVal, mNavigationBarView.getBarTransitions(),
-                    View.NAVIGATION_BAR_TRANSIENT, View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION);
+                    View.NAVIGATION_BAR_TRANSIENT, View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION,
+                    mNavigationBarWindowState);
 
             if (sbMode != -1 || nbMode != -1) {
                 // update transient bar autohide
@@ -1919,19 +1910,29 @@ public class PhoneStatusBar extends BaseStatusBar {
                 }
             }
 
+            // ready to unhide
+            if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
+                mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
+            }
+            if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
+                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
+            }
+
             // send updated sysui visibility to window manager
             notifyUiVisibilityChanged(mSystemUiVisibility);
         }
     }
 
     private int updateBarMode(int oldVis, int newVis, BarTransitions transitions,
-            int transientFlag, int transparentFlag) {
+            int transientFlag, int transparentFlag, int windowState) {
         final int oldMode = barMode(oldVis, transientFlag, transparentFlag);
         final int newMode = barMode(newVis, transientFlag, transparentFlag);
         if (oldMode == newMode) {
             return -1; // no mode change
         }
-        transitions.transitionTo(newMode);
+        boolean animate = windowState == StatusBarManager.WINDOW_STATE_SHOWING
+                && oldMode == MODE_SEMI_TRANSPARENT && newMode == MODE_OPAQUE;
+        transitions.transitionTo(newMode, animate);
         return newMode;
     }
 
@@ -1941,11 +1942,19 @@ public class PhoneStatusBar extends BaseStatusBar {
                 : MODE_OPAQUE;
     }
 
+    private final Runnable mResumeSemiTransparent = new Runnable() {
+        @Override
+        public void run() {
+            if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0) {
+                animateTransitionTo(BarTransitions.MODE_SEMI_TRANSPARENT);
+            }
+        }};
+
     @Override
     public void resumeAutohide() {
         if (mAutohideSuspended) {
             scheduleAutohide();
-            animateTransitionTo(BarTransitions.MODE_SEMI_TRANSPARENT);
+            mHandler.postDelayed(mResumeSemiTransparent, 500); // longer than home -> launcher
         }
     }
 
@@ -1959,7 +1968,8 @@ public class PhoneStatusBar extends BaseStatusBar {
     @Override
     public void suspendAutohide() {
         mHandler.removeCallbacks(mAutohide);
-        mAutohideSuspended = 0 != (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT);
+        mHandler.removeCallbacks(mResumeSemiTransparent);
+        mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
         animateTransitionTo(BarTransitions.MODE_OPAQUE);
     }
 
@@ -1984,7 +1994,7 @@ public class PhoneStatusBar extends BaseStatusBar {
 
     private void userAutohide() {
         cancelAutohide();
-        mHandler.postDelayed(mAutohide, 25);
+        mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
     }
 
     private void setStatusBarLowProfile(boolean lightsOut) {
index fb76e20..bcecff2 100644 (file)
@@ -40,18 +40,21 @@ public class BarController {
 
     private final String mTag;
     private final int mTransientFlag;
+    private final int mUnhideFlag;
     private final int mStatusBarManagerId;
     private final Handler mHandler;
     private final Object mServiceAquireLock = new Object();
     private IStatusBarService mStatusBarService;
 
     private WindowState mWin;
+    private int mState;
     private int mTransientBarState;
     private boolean mPendingShow;
 
-    public BarController(String tag, int transientFlag, int statusBarManagerId) {
+    public BarController(String tag, int transientFlag, int unhideFlag, int statusBarManagerId) {
         mTag = "BarController." + tag;
         mTransientFlag = transientFlag;
+        mUnhideFlag = unhideFlag;
         mStatusBarManagerId = statusBarManagerId;
         mHandler = new Handler();
     }
@@ -60,6 +63,10 @@ public class BarController {
         mWin = win;
     }
 
+    public boolean isHidden() {
+        return mState == StatusBarManager.WINDOW_STATE_HIDDEN;
+    }
+
     public void showTransient() {
         if (mWin != null) {
             setTransientBarState(TRANSIENT_BAR_SHOWING);
@@ -70,49 +77,75 @@ public class BarController {
         return mTransientBarState == TRANSIENT_BAR_SHOWING;
     }
 
-    public void adjustSystemUiVisibilityLw(int visibility) {
+    public void adjustSystemUiVisibilityLw(int oldVis, int vis) {
         if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING &&
-                (visibility & mTransientFlag) == 0) {
+                (vis & mTransientFlag) == 0) {
+            // sysui requests hide
             setTransientBarState(TRANSIENT_BAR_HIDING);
             setBarShowingLw(false);
+        } else if (mWin != null && (oldVis & mUnhideFlag) != 0 && (vis & mUnhideFlag) == 0) {
+            // sysui ready to unhide
+            setBarShowingLw(true);
         }
     }
 
     public boolean setBarShowingLw(final boolean show) {
         if (mWin == null) return false;
-
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    IStatusBarService statusbar = getStatusBarService();
-                    if (statusbar != null) {
-                        statusbar.setWindowState(mStatusBarManagerId, show
-                                ? StatusBarManager.WINDOW_STATE_SHOWING
-                                : StatusBarManager.WINDOW_STATE_HIDING);
-                    }
-                } catch (RemoteException e) {
-                    // re-acquire status bar service next time it is needed.
-                    mStatusBarService = null;
-                }
-            }
-        });
         if (show && mTransientBarState == TRANSIENT_BAR_HIDING) {
             mPendingShow = true;
             return false;
         }
-        return show ? mWin.showLw(true) : mWin.hideLw(true);
+        final boolean oldVis = mWin.isVisibleLw();
+        final boolean oldAnim = mWin.isAnimatingLw();
+        final boolean rt = show ? mWin.showLw(true) : mWin.hideLw(true);
+        final int state = computeState(oldVis, oldAnim, mWin.isVisibleLw(), mWin.isAnimatingLw());
+        if (state > -1) {
+            updateState(state);
+        }
+        return rt;
+    }
+
+    private int computeState(boolean oldVis, boolean oldAnim, boolean newVis, boolean newAnim) {
+        return (!newVis && !newAnim) ? StatusBarManager.WINDOW_STATE_HIDDEN
+                : (!oldVis && newVis && newAnim) ? StatusBarManager.WINDOW_STATE_SHOWING
+                : (oldVis && newVis && !oldAnim && newAnim) ? StatusBarManager.WINDOW_STATE_HIDING
+                : -1;
+    }
+
+    private void updateState(final int state) {
+        if (state != mState) {
+            mState = state;
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        IStatusBarService statusbar = getStatusBarService();
+                        if (statusbar != null) {
+                            statusbar.setWindowState(mStatusBarManagerId, state);
+                        }
+                    } catch (RemoteException e) {
+                        // re-acquire status bar service next time it is needed.
+                        mStatusBarService = null;
+                    }
+                }
+            });
+        }
     }
 
     public boolean checkHiddenLw() {
-        if (mWin != null && mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) {
-            // Finished animating out, clean up and reset style
-            setTransientBarState(TRANSIENT_BAR_NONE);
-            if (mPendingShow) {
-                setBarShowingLw(true);
-                mPendingShow = false;
+        if (mWin != null) {
+            if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
+                updateState(StatusBarManager.WINDOW_STATE_HIDDEN);
+            }
+            if (mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) {
+                // Finished animating out, clean up and reset style
+                setTransientBarState(TRANSIENT_BAR_NONE);
+                if (mPendingShow) {
+                    setBarShowingLw(true);
+                    mPendingShow = false;
+                }
+                return true;
             }
-            return true;
         }
         return false;
     }
@@ -134,12 +167,11 @@ public class BarController {
 
     public int updateVisibilityLw(boolean allowed, int oldVis, int vis) {
         if (mWin == null) return vis;
-
         if (mTransientBarState == TRANSIENT_BAR_SHOWING) { // transient bar requested
             if (allowed) {
                 vis |= mTransientFlag;
                 if ((oldVis & mTransientFlag) == 0) {
-                    setBarShowingLw(true);
+                    vis |= mUnhideFlag;  // tell sysui we're ready to unhide
                 }
             } else {
                 setTransientBarState(TRANSIENT_BAR_NONE);  // request denied
index 11e33dc..f3e7f0a 100644 (file)
@@ -554,9 +554,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
     MyOrientationListener mOrientationListener;
 
     private final BarController mStatusBarController = new BarController("StatusBar",
-            View.STATUS_BAR_TRANSIENT, StatusBarManager.WINDOW_STATUS_BAR);
+            View.STATUS_BAR_TRANSIENT,
+            View.STATUS_BAR_UNHIDE,
+            StatusBarManager.WINDOW_STATUS_BAR);
+
     private final BarController mNavigationBarController = new BarController("NavigationBar",
-            View.NAVIGATION_BAR_TRANSIENT, StatusBarManager.WINDOW_NAVIGATION_BAR);
+            View.NAVIGATION_BAR_TRANSIENT,
+            View.NAVIGATION_BAR_UNHIDE,
+            StatusBarManager.WINDOW_NAVIGATION_BAR);
+
     private TransientNavigationConfirmation mTransientNavigationConfirmation;
 
     private SystemGesturesPointerEventListener mSystemGestures;
@@ -2551,8 +2557,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
 
     @Override
     public int adjustSystemUiVisibilityLw(int visibility) {
-        mStatusBarController.adjustSystemUiVisibilityLw(visibility);
-        mNavigationBarController.adjustSystemUiVisibilityLw(visibility);
+        mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
+        mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
 
         // Reset any bits in mForceClearingStatusBarVisibility that
         // are now clear.
@@ -5084,6 +5090,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         }
         vis = mNavigationBarController.updateVisibilityLw(isTransientNav, oldVis, vis);
 
+        // don't send low profile updates if the system bars are hidden
+        if (mStatusBarController.isHidden() && mNavigationBarController.isHidden()) {
+            vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
+        }
         return vis;
     }