Improve transparent bar transitions.

1. Migrate transparent transitions to the new optimized
background color animations.

2. Ensure sysui animation transparent -> opaque has enough
time to run before window manager crops off the content area.

3. Lose the individual alpha on each status bar icon if the bars
are not opaque.  Animate the alpha if visible, make sure they
play together.

4. Documentation typo fix found in AnimatorSet.

Bug:10344949
Change-Id: I615668ce3c552d3df15dbba5cdeeca67549a0220
diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java
index 14d3d19..71c7450 100644
--- a/core/java/android/view/animation/AnimationSet.java
+++ b/core/java/android/view/animation/AnimationSet.java
@@ -114,7 +114,7 @@
      * Constructor to use when building an AnimationSet from code
      * 
      * @param shareInterpolator Pass true if all of the animations in this set
-     *        should use the interpolator assocciated with this AnimationSet.
+     *        should use the interpolator associated with this AnimationSet.
      *        Pass false if each animation should use its own interpolator.
      */
     public AnimationSet(boolean shareInterpolator) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index a3b492c..24f7d83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -70,6 +70,7 @@
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SearchPanelView;
 import com.android.systemui.SystemUI;
+import com.android.systemui.statusbar.phone.BarTransitions;
 import com.android.systemui.statusbar.policy.NotificationRowLayout;
 
 import java.util.ArrayList;
@@ -827,7 +828,7 @@
         // Construct the icon.
         final StatusBarIconView iconView = new StatusBarIconView(mContext,
                 notification.getPackageName() + "/0x" + Integer.toHexString(notification.getId()),
-                notification.getNotification());
+                notification.getNotification(), getStatusBarMode());
         iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
 
         final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
@@ -850,6 +851,10 @@
         return entry;
     }
 
+    protected int getStatusBarMode() {
+        return BarTransitions.MODE_OPAQUE;
+    }
+
     protected void addNotificationViews(NotificationData.Entry entry) {
         // Add the expanded view and icon.
         int pos = mNotificationData.add(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 5bda813..5689bfa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -16,6 +16,11 @@
 
 package com.android.systemui.statusbar;
 
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
+
+import android.animation.ObjectAnimator;
 import android.app.Notification;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -48,10 +53,13 @@
     private int mNumberY;
     private String mNumberText;
     private Notification mNotification;
+    private final float mAlphaWhenOpaque;
+    private final float mAlphaWhenTransparent = 1;
 
-    public StatusBarIconView(Context context, String slot, Notification notification) {
+    public StatusBarIconView(Context context, String slot, Notification notification, int mode) {
         super(context);
         final Resources res = context.getResources();
+        mAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
         mSlot = slot;
         mNumberPain = new Paint();
         mNumberPain.setTextAlign(Paint.Align.CENTER);
@@ -68,8 +76,7 @@
             final float scale = (float)imageBounds / (float)outerBounds;
             setScaleX(scale);
             setScaleY(scale);
-            final float alpha = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
-            setAlpha(alpha);
+            setAlpha(getAlphaFor(mode));
         }
 
         setScaleType(ImageView.ScaleType.CENTER);
@@ -78,13 +85,22 @@
     public StatusBarIconView(Context context, AttributeSet attrs) {
         super(context, attrs);
         final Resources res = context.getResources();
+        mAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
         final int outerBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
         final int imageBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size);
         final float scale = (float)imageBounds / (float)outerBounds;
         setScaleX(scale);
         setScaleY(scale);
-        final float alpha = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
-        setAlpha(alpha);
+        setAlpha(getAlphaFor(MODE_OPAQUE));
+    }
+
+    public ObjectAnimator animateTransitionTo(int mode) {
+        return ObjectAnimator.ofFloat(this, "alpha", getAlpha(), getAlphaFor(mode));
+    }
+
+    public float getAlphaFor(int mode) {
+        final boolean isTransparent = mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSPARENT;
+        return isTransparent ? mAlphaWhenTransparent : mAlphaWhenOpaque;
     }
 
     private static boolean streq(String a, String b) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 292ea7c..318ec51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -60,6 +60,10 @@
         mSemiTransparent = res.getColor(R.color.status_bar_background_semi_transparent);
     }
 
+    public int getMode() {
+        return mMode;
+    }
+
     public void setTransparent(Drawable transparent) {
         mTransparent = transparent;
         if (mMode == MODE_TRANSPARENT) {
@@ -80,16 +84,24 @@
         onTransition(oldMode, mMode, animate);
     }
 
+    protected Integer getBackgroundColor(int mode) {
+        if (mode == MODE_SEMI_TRANSPARENT) return mSemiTransparent;
+        if (mode == MODE_OPAQUE) return mOpaque;
+        return null;
+    }
+
     protected void onTransition(int oldMode, int newMode, boolean animate) {
         cancelBackgroundColorAnimation();
-        if (animate && oldMode == MODE_SEMI_TRANSPARENT && newMode == MODE_OPAQUE) {
-            startBackgroundColorAnimation(mSemiTransparent, mOpaque);
-        } else if (animate && oldMode == MODE_OPAQUE && newMode == MODE_SEMI_TRANSPARENT) {
-            startBackgroundColorAnimation(mOpaque, mSemiTransparent);
-        } else if (newMode == MODE_OPAQUE || newMode == MODE_SEMI_TRANSPARENT) {
-            mTarget.setBackgroundColor(newMode == MODE_OPAQUE ? mOpaque : mSemiTransparent);
+        Integer oldColor = getBackgroundColor(oldMode);
+        Integer newColor = getBackgroundColor(newMode);
+        if (oldColor != null && newColor != null) {
+            if (animate) {
+                startBackgroundColorAnimation(oldColor, newColor);
+            } else {
+                mTarget.setBackgroundColor(newColor);
+            }
         } else {
-            mTarget.setBackground(newMode == MODE_TRANSPARENT? mTransparent
+            mTarget.setBackground(newMode == MODE_TRANSPARENT ? mTransparent
                     : newMode == MODE_SEMI_TRANSPARENT ? new ColorDrawable(mSemiTransparent)
                     : new ColorDrawable(mOpaque));
         }
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 02346d9..fffb130 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -843,7 +843,7 @@
     public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
         if (SPEW) Log.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
                 + " icon=" + icon);
-        StatusBarIconView view = new StatusBarIconView(mContext, slot, null);
+        StatusBarIconView view = new StatusBarIconView(mContext, slot, null, getStatusBarMode());
         view.set(icon);
         mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize));
     }
@@ -1921,6 +1921,11 @@
         }
     }
 
+    @Override
+    protected int getStatusBarMode() {
+        return mStatusBarView.getBarTransitions().getMode();
+    }
+
     private int updateBarMode(int oldVis, int newVis, BarTransitions transitions,
             int transientFlag, int transparentFlag, int windowState) {
         final int oldMode = barMode(oldVis, transientFlag, transparentFlag);
@@ -1928,8 +1933,7 @@
         if (oldMode == newMode) {
             return -1; // no mode change
         }
-        boolean animate = windowState == StatusBarManager.WINDOW_STATE_SHOWING
-                && oldMode == MODE_SEMI_TRANSPARENT && newMode == MODE_OPAQUE;
+        final boolean animate = windowState == StatusBarManager.WINDOW_STATE_SHOWING;
         transitions.transitionTo(newMode, animate);
         return newMode;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 910d4c4..2e9ee87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -16,20 +16,26 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.animation.Animator;
+import android.animation.AnimatorSet;
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarIconView;
+
+import java.util.ArrayList;
+import java.util.List;
 
 public class PhoneStatusBarView extends PanelBar {
     private static final String TAG = "PhoneStatusBarView";
@@ -49,10 +55,56 @@
     private final StatusBarTransitions mBarTransitions;
 
     private final class StatusBarTransitions extends BarTransitions {
+        private final int mTransparent;
+
         public StatusBarTransitions(Context context) {
             super(context, PhoneStatusBarView.this);
             final Resources res = context.getResources();
-            mTransparent = res.getDrawable(R.color.status_bar_background_transparent);
+            mTransparent = res.getColor(R.color.status_bar_background_transparent);
+        }
+
+        @Override
+        protected Integer getBackgroundColor(int mode) {
+            if (mode == MODE_TRANSPARENT) return mTransparent;
+            return super.getBackgroundColor(mode);
+        }
+
+        @Override
+        protected void onTransition(int oldMode, int newMode, boolean animate) {
+            super.onTransition(oldMode, newMode, animate);
+            if (animate) {
+                List<Animator> animators = new ArrayList<Animator>();
+                for(StatusBarIconView icon : findStatusBarIcons()) {
+                    animators.add(icon.animateTransitionTo(newMode));
+                }
+                AnimatorSet set = new AnimatorSet();
+                set.playTogether(animators);
+                set.start();
+            } else {
+                for(StatusBarIconView icon : findStatusBarIcons()) {
+                    icon.setAlpha(icon.getAlphaFor(newMode));
+                }
+            }
+        }
+
+        private List<StatusBarIconView> findStatusBarIcons() {
+            List<StatusBarIconView> icons = new ArrayList<StatusBarIconView>();
+            findStatusBarIcons(icons, findViewById(R.id.moreIcon));
+            findStatusBarIcons(icons, findViewById(R.id.statusIcons));
+            findStatusBarIcons(icons, findViewById(R.id.notificationIcons));
+            return icons;
+        }
+
+        private void findStatusBarIcons(List<StatusBarIconView> icons, View v) {
+            if (v instanceof StatusBarIconView) {
+                icons.add((StatusBarIconView) v);
+            } else if (v instanceof ViewGroup) {
+                ViewGroup group = (ViewGroup) v;
+                final int N = group.getChildCount();
+                for (int i = 0; i < N; i++) {
+                    findStatusBarIcons(icons, group.getChildAt(i));
+                }
+            }
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
index bcecff2..554fd1cc 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -20,6 +20,7 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.util.Slog;
 import android.view.View;
 import android.view.WindowManagerPolicy.WindowState;
@@ -38,9 +39,12 @@
     private static final int TRANSIENT_BAR_SHOWING = 1;
     private static final int TRANSIENT_BAR_HIDING = 2;
 
+    private static final int TRANSPARENT_ANIMATION_DELAY_MS = 1000;
+
     private final String mTag;
     private final int mTransientFlag;
     private final int mUnhideFlag;
+    private final int mTransparentFlag;
     private final int mStatusBarManagerId;
     private final Handler mHandler;
     private final Object mServiceAquireLock = new Object();
@@ -50,11 +54,14 @@
     private int mState;
     private int mTransientBarState;
     private boolean mPendingShow;
+    private long mLastTransparent;
 
-    public BarController(String tag, int transientFlag, int unhideFlag, int statusBarManagerId) {
+    public BarController(String tag, int transientFlag, int unhideFlag, int transparentFlag,
+            int statusBarManagerId) {
         mTag = "BarController." + tag;
         mTransientFlag = transientFlag;
         mUnhideFlag = unhideFlag;
+        mTransparentFlag = transparentFlag;
         mStatusBarManagerId = statusBarManagerId;
         mHandler = new Handler();
     }
@@ -77,6 +84,10 @@
         return mTransientBarState == TRANSIENT_BAR_SHOWING;
     }
 
+    public boolean wasRecentlyTransparent() {
+        return (SystemClock.uptimeMillis() - mLastTransparent) < TRANSPARENT_ANIMATION_DELAY_MS;
+    }
+
     public void adjustSystemUiVisibilityLw(int oldVis, int vis) {
         if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING &&
                 (vis & mTransientFlag) == 0) {
@@ -181,11 +192,17 @@
             vis |= mTransientFlag;  // ignore clear requests until transition completes
             vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;  // never show transient bars in low profile
         }
+        if ((vis & mTransparentFlag) != 0 || (oldVis & mTransparentFlag) != 0) {
+            mLastTransparent = SystemClock.uptimeMillis();
+        }
         return vis;
     }
 
     private void setTransientBarState(int state) {
         if (mWin != null && state != mTransientBarState) {
+            if (mTransientBarState == TRANSIENT_BAR_SHOWING || state == TRANSIENT_BAR_SHOWING) {
+                mLastTransparent = SystemClock.uptimeMillis();
+            }
             mTransientBarState = state;
             if (DEBUG) Slog.d(mTag, "New state: " + transientBarStateToString(state));
         }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index f3e7f0a..da98f27 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -556,11 +556,13 @@
     private final BarController mStatusBarController = new BarController("StatusBar",
             View.STATUS_BAR_TRANSIENT,
             View.STATUS_BAR_UNHIDE,
+            View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS,
             StatusBarManager.WINDOW_STATUS_BAR);
 
     private final BarController mNavigationBarController = new BarController("NavigationBar",
             View.NAVIGATION_BAR_TRANSIENT,
             View.NAVIGATION_BAR_UNHIDE,
+            View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION,
             StatusBarManager.WINDOW_NAVIGATION_BAR);
 
     private TransientNavigationConfirmation mTransientNavigationConfirmation;
@@ -2739,7 +2741,8 @@
                         // We currently want to hide the navigation UI.
                         mNavigationBarController.setBarShowingLw(false);
                     }
-                    if (navVisible && !navTransparent && !mNavigationBar.isAnimatingLw()) {
+                    if (navVisible && !navTransparent && !mNavigationBar.isAnimatingLw()
+                            && !mNavigationBarController.wasRecentlyTransparent()) {
                         // If the opaque nav bar is currently requested to be visible,
                         // and not in the process of animating on or off, then
                         // we can tell the app that it is covered by it.
@@ -2762,7 +2765,8 @@
                         // We currently want to hide the navigation UI.
                         mNavigationBarController.setBarShowingLw(false);
                     }
-                    if (navVisible && !navTransparent && !mNavigationBar.isAnimatingLw()) {
+                    if (navVisible && !navTransparent && !mNavigationBar.isAnimatingLw()
+                            && !mNavigationBarController.wasRecentlyTransparent()) {
                         // If the nav bar is currently requested to be visible,
                         // and not in the process of animating on or off, then
                         // we can tell the app that it is covered by it.
@@ -2832,7 +2836,8 @@
                             mCurLeft, mCurTop, mCurRight, mCurBottom));
                 }
                 if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()
-                        && !statusBarTransient && !statusBarTransparent) {
+                        && !statusBarTransient && !statusBarTransparent
+                        && !mStatusBarController.wasRecentlyTransparent()) {
                     // If the opaque status bar is currently requested to be visible,
                     // and not in the process of animating on or off, then
                     // we can tell the app that it is covered by it.
@@ -5011,7 +5016,7 @@
         if (mForcingShowNavBar && mFocusedWindow.getSurfaceLayer() < mForcingShowNavBarLayer) {
             tmpVisibility &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
         }
-        final int visibility = updateTransientBarsLw(mLastSystemUiFlags, tmpVisibility);
+        final int visibility = updateSystemBarsLw(mLastSystemUiFlags, tmpVisibility);
         final int diff = visibility ^ mLastSystemUiFlags;
         final boolean needsMenu = mFocusedWindow.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
         if (diff == 0 && mLastFocusNeedsMenu == needsMenu
@@ -5039,7 +5044,7 @@
         return diff;
     }
 
-    private int updateTransientBarsLw(int oldVis, int vis) {
+    private int updateSystemBarsLw(int oldVis, int vis) {
         if (ImmersiveModeTesting.enabled) {
             vis = ImmersiveModeTesting.applyForced(mFocusedWindow, vis);
         }