Merge "Tweak recents out animation a bit more" into jb-dev
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index 8a21117..00e3e27 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -26,7 +26,11 @@
     android:layout_width="match_parent"
     systemui:recentItemLayout="@layout/status_bar_recent_item"
     >
-
+    <View
+        android:id="@+id/recents_transition_background"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:visibility="invisible" />
     <FrameLayout
         android:id="@+id/recents_bg_protect"
         android:background="@drawable/status_bar_recents_background"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
index 1d29c5a..a7e5db1 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -26,7 +26,11 @@
     android:layout_width="match_parent"
     systemui:recentItemLayout="@layout/status_bar_recent_item"
     >
-
+    <View
+        android:id="@+id/recents_transition_background"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:visibility="invisible" />
     <FrameLayout
         android:id="@+id/recents_bg_protect"
         android:background="@drawable/status_bar_recents_background"
diff --git a/packages/SystemUI/res/layout/system_bar_recent_panel.xml b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
index d5745c8..127551d 100644
--- a/packages/SystemUI/res/layout/system_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
@@ -28,7 +28,11 @@
     android:clipChildren="false"
     systemui:recentItemLayout="@layout/system_bar_recent_item"
     >
-
+    <View
+        android:id="@+id/recents_transition_background"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:visibility="invisible" />
     <FrameLayout
         android:id="@+id/recents_bg_protect"
         android:background="@drawable/recents_bg_protect_tile"
@@ -38,7 +42,6 @@
         android:layout_marginBottom="@*android:dimen/system_bar_height"
         android:clipToPadding="false"
         android:clipChildren="false">
-
         <ImageView
             android:id="@+id/recents_transition_placeholder_icon"
             android:layout_width="wrap_content"
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
index ccdf038..296b640 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
@@ -20,15 +20,19 @@
 import android.animation.AnimatorSet;
 import android.animation.AnimatorSet.Builder;
 import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.Slog;
 import android.view.View;
 import android.view.ViewRootImpl;
 
+import com.android.systemui.R;
+
 /* package */ class Choreographer implements Animator.AnimatorListener {
     // should group this into a multi-property animation
     private static final int OPEN_DURATION = 136;
-    private static final int CLOSE_DURATION = 130;
+    private static final int CLOSE_DURATION = 230;
     private static final int SCRIM_DURATION = 400;
     private static final String TAG = RecentsPanelView.TAG;
     private static final boolean DEBUG = RecentsPanelView.DEBUG;
@@ -81,7 +85,7 @@
                 mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
         fadeAnim.setInterpolator(appearing
                 ? new android.view.animation.AccelerateInterpolator(1.0f)
-                : new android.view.animation.DecelerateInterpolator(1.0f));
+                : new android.view.animation.AccelerateInterpolator(2.5f));
         fadeAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
 
         Animator noRecentAppsFadeAnim = null;
@@ -110,6 +114,20 @@
                 bgAnim.setDuration(appearing ? SCRIM_DURATION : CLOSE_DURATION);
                 builder.with(bgAnim);
             }
+        } else {
+            final Resources res = mRootView.getResources();
+            boolean isTablet = res.getBoolean(R.bool.config_recents_interface_for_tablets);
+            if (!isTablet) {
+                View recentsTransitionBackground =
+                        mRootView.findViewById(R.id.recents_transition_background);
+                recentsTransitionBackground.setVisibility(View.VISIBLE);
+                Drawable bgDrawable = new ColorDrawable(0xFF000000);
+                recentsTransitionBackground.setBackground(bgDrawable);
+                Animator bgAnim = ObjectAnimator.ofInt(bgDrawable, "alpha", 0, 255);
+                bgAnim.setDuration(CLOSE_DURATION);
+                bgAnim.setInterpolator(new android.view.animation.AccelerateInterpolator(1f));
+                builder.with(bgAnim);
+            }
         }
         mContentAnim.addListener(this);
         if (mListener != null) {
@@ -139,6 +157,10 @@
         if (mScrimView.getBackground() != null) {
             mScrimView.getBackground().setAlpha(appearing ? 255 : 0);
         }
+        View recentsTransitionBackground =
+                mRootView.findViewById(R.id.recents_transition_background);
+        recentsTransitionBackground.setVisibility(View.INVISIBLE);
+        mRootView.requestLayout();
     }
 
     public void setPanelHeight(int h) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 34cd397..bec9aa2 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -34,11 +34,13 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Display;
 import android.view.KeyEvent;
+import android.view.IWindowManager;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
@@ -86,7 +88,8 @@
     OnRecentsPanelVisibilityChangedListener mVisibilityChangedListener;
 
     ImageView mPlaceholderThumbnail;
-    boolean mHideWindowAfterPlaceholderThumbnailIsHidden;
+    View mTransitionBg;
+    boolean mHideRecentsAfterThumbnailScaleUpStarted;
 
     private RecentTasksLoader mRecentTasksLoader;
     private ArrayList<TaskDescription> mRecentTaskDescriptions;
@@ -97,6 +100,7 @@
     private boolean mFitThumbnailToXY;
     private int mRecentItemLayoutId;
     private boolean mFirstScreenful = true;
+    private boolean mHighEndGfx;
 
     public static interface OnRecentsPanelVisibilityChangedListener {
         public void onRecentsPanelVisibilityChanged(boolean visible);
@@ -248,7 +252,7 @@
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_BACK && !event.isCanceled()) {
-            show(false, true);
+            show(false, false);
             return true;
         }
         return super.onKeyUp(keyCode, event);
@@ -305,10 +309,6 @@
             ArrayList<TaskDescription> recentTaskDescriptions, boolean firstScreenful) {
         sendCloseSystemWindows(mContext, BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
 
-        // For now, disable animations. We may want to re-enable in the future
-        if (show) {
-            animate = false;
-        }
         if (show) {
             // Need to update list of recent apps before we set visibility so this view's
             // content description is updated before it gets focus for TalkBack mode
@@ -318,6 +318,7 @@
             // quit early
             boolean noApps = !mFirstScreenful && (mRecentTaskDescriptions.size() == 0);
             if (mRecentsNoApps != null) {
+                mRecentsNoApps.setAlpha(1f);
                 mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
             } else {
                 if (noApps) {
@@ -339,7 +340,6 @@
             mRecentTasksDirty = true;
             mWaitingToShow = false;
             mReadyToShow = false;
-            mRecentsNoApps.setVisibility(View.INVISIBLE);
         }
         if (animate) {
             if (mShowing != show) {
@@ -488,7 +488,8 @@
         if (mRecentsScrim != null) {
             Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
                 .getDefaultDisplay();
-            if (!ActivityManager.isHighEndGfx(d)) {
+            mHighEndGfx = ActivityManager.isHighEndGfx(d);
+            if (!mHighEndGfx) {
                 mRecentsScrim.setBackground(null);
             } else if (mRecentsScrim.getBackground() instanceof BitmapDrawable) {
                 // In order to save space, we make the background texture repeat in the Y direction
@@ -704,22 +705,57 @@
         setContentDescription(recentAppsAccessibilityDescription);
     }
 
+
+    boolean mThumbnailScaleUpStarted;
     public void handleOnClick(View view) {
         ViewHolder holder = (ViewHolder)view.getTag();
         TaskDescription ad = holder.taskDescription;
         final Context context = view.getContext();
         final ActivityManager am = (ActivityManager)
                 context.getSystemService(Context.ACTIVITY_SERVICE);
-        holder.thumbnailViewImage.setDrawingCacheEnabled(true);
-        Bitmap bm = holder.thumbnailViewImage.getDrawingCache();
-        mPlaceholderThumbnail = (ImageView) findViewById(R.id.recents_transition_placeholder_icon);
+        Bitmap bm = holder.thumbnailViewImageBitmap;
+        boolean usingDrawingCache;
+        if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
+                bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
+            usingDrawingCache = false;
+        } else {
+            holder.thumbnailViewImage.setDrawingCacheEnabled(true);
+            bm = holder.thumbnailViewImage.getDrawingCache();
+            usingDrawingCache = true;
+        }
+
+        if (mPlaceholderThumbnail == null) {
+            mPlaceholderThumbnail =
+                    (ImageView) findViewById(R.id.recents_transition_placeholder_icon);
+        }
+        if (mTransitionBg == null) {
+            mTransitionBg = (View) findViewById(R.id.recents_transition_background);
+
+            IWindowManager wm = IWindowManager.Stub.asInterface(
+                    ServiceManager.getService(Context.WINDOW_SERVICE));
+            try {
+                if (!wm.hasSystemNavBar()) {
+                    FrameLayout.LayoutParams lp =
+                            (FrameLayout.LayoutParams) mTransitionBg.getLayoutParams();
+                    int statusBarHeight = getResources().
+                            getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+                    lp.setMargins(0, statusBarHeight, 0, 0);
+                    mTransitionBg.setLayoutParams(lp);
+                }
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failing checking whether status bar is visible", e);
+            }
+        }
 
         final ImageView placeholderThumbnail = mPlaceholderThumbnail;
-        mHideWindowAfterPlaceholderThumbnailIsHidden = false;
+        mHideRecentsAfterThumbnailScaleUpStarted = false;
         placeholderThumbnail.setVisibility(VISIBLE);
-        Bitmap b2 = bm.copy(bm.getConfig(), true);
-        placeholderThumbnail.setImageBitmap(b2);
-
+        if (!usingDrawingCache) {
+            placeholderThumbnail.setImageBitmap(bm);
+        } else {
+            Bitmap b2 = bm.copy(bm.getConfig(), true);
+            placeholderThumbnail.setImageBitmap(b2);
+        }
         Rect r = new Rect();
         holder.thumbnailViewImage.getGlobalVisibleRect(r);
 
@@ -728,13 +764,16 @@
 
         show(false, true);
 
+        mThumbnailScaleUpStarted = false;
         ActivityOptions opts = ActivityOptions.makeDelayedThumbnailScaleUpAnimation(
                 holder.thumbnailViewImage, bm, 0, 0,
                 new ActivityOptions.OnAnimationStartedListener() {
                     @Override public void onAnimationStarted() {
-                        mPlaceholderThumbnail = null;
-                        placeholderThumbnail.setVisibility(INVISIBLE);
-                        if (mHideWindowAfterPlaceholderThumbnailIsHidden) {
+                        mThumbnailScaleUpStarted = true;
+                        if (!mHighEndGfx) {
+                            mPlaceholderThumbnail.setVisibility(INVISIBLE);
+                        }
+                        if (mHideRecentsAfterThumbnailScaleUpStarted) {
                             hideWindow();
                         }
                     }
@@ -751,15 +790,19 @@
             if (DEBUG) Log.v(TAG, "Starting activity " + intent);
             context.startActivity(intent, opts.toBundle());
         }
-        holder.thumbnailViewImage.setDrawingCacheEnabled(false);
+        if (!usingDrawingCache) {
+            holder.thumbnailViewImage.setDrawingCacheEnabled(false);
+        }
     }
 
     public void hideWindow() {
-        if (mPlaceholderThumbnail != null) {
-            mHideWindowAfterPlaceholderThumbnailIsHidden = true;
+        if (!mThumbnailScaleUpStarted) {
+            mHideRecentsAfterThumbnailScaleUpStarted = true;
         } else {
             setVisibility(GONE);
-            mHideWindowAfterPlaceholderThumbnailIsHidden = false;
+            mTransitionBg.setVisibility(INVISIBLE);
+            mPlaceholderThumbnail.setVisibility(INVISIBLE);
+            mHideRecentsAfterThumbnailScaleUpStarted = false;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index d387515..e802985 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -76,9 +76,6 @@
     }
 
     private void addToRecycledViews(View v) {
-        if (mRecycledViews.contains(v)) {
-            throw new RuntimeException("Child was already recycled");
-        }
         if (mRecycledViews.size() < mNumItemsInOneScreenful) {
             mRecycledViews.add(v);
         }
@@ -105,9 +102,6 @@
                 old = recycledViews.next();
                 recycledViews.remove();
                 old.setVisibility(VISIBLE);
-                if (old.getParent() != null) {
-                    throw new RuntimeException("Recycled child has parent (i: " + i + ", recycled i: " + mRecycledViews.size());
-                }
             }
             final View view = mAdapter.getView(i, old, mLinearLayout);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index cf2690b..750c6dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -440,13 +440,13 @@
              case MSG_OPEN_RECENTS_PANEL:
                   if (DEBUG) Slog.d(TAG, "opening recents panel");
                   if (mRecentsPanel != null) {
-                      mRecentsPanel.show(true, true);
+                      mRecentsPanel.show(true, false);
                   }
                   break;
              case MSG_CLOSE_RECENTS_PANEL:
                   if (DEBUG) Slog.d(TAG, "closing recents panel");
                   if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
-                      mRecentsPanel.show(false, true);
+                      mRecentsPanel.show(false, false);
                   }
                   break;
              case MSG_PRELOAD_RECENT_APPS:
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index ba4df96b..28c8b06 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -127,6 +127,7 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationSet;
 import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.ScaleAnimation;
 
@@ -280,6 +281,8 @@
     private static final int ALLOW_DISABLE_UNKNOWN = -1; // check with DevicePolicyManager
     private int mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN; // sync'd by mKeyguardTokenWatcher
 
+    private static final float THUMBNAIL_ANIMATION_DECELERATE_FACTOR = 1.5f;
+
     final TokenWatcher mKeyguardTokenWatcher = new TokenWatcher(
             new Handler(), "WindowManagerService.mKeyguardTokenWatcher") {
         @Override
@@ -3183,7 +3186,7 @@
         // it  is the standard duration for that.  Otherwise we use the longer
         // task transition duration.
         int duration;
-        int delayDuration = delayed ? 200 : 0;
+        int delayDuration = delayed ? 270 : 0;
         switch (transit) {
             case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
             case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
@@ -3191,7 +3194,7 @@
                         com.android.internal.R.integer.config_shortAnimTime);
                 break;
             default:
-                duration = delayed ? 200 : 300;
+                duration = delayed ? 250 : 300;
                 break;
         }
         if (thumb) {
@@ -3206,6 +3209,8 @@
             AnimationSet set = new AnimationSet(true);
             Animation alpha = new AlphaAnimation(1, 0);
             scale.setDuration(duration);
+            scale.setInterpolator(
+                    new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
             set.addAnimation(scale);
             alpha.setDuration(duration);
             set.addAnimation(alpha);
@@ -3222,6 +3227,8 @@
                     computePivot(mNextAppTransitionStartX, scaleW),
                     computePivot(mNextAppTransitionStartY, scaleH));
             scale.setDuration(duration);
+            scale.setInterpolator(
+                    new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
             scale.setFillBefore(true);
             if (delayDuration > 0) {
                 scale.setStartOffset(delayDuration);