Merge "Hide recents during freeform to recents animation."
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 0266a37..6107dfd 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -131,6 +131,13 @@
     public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener";
 
     /**
+     * Callback for when the last frame of the animation is played.
+     * @hide
+     */
+    private static final String KEY_ANIMATION_FINISHED_LISTENER =
+            "android:activity.animationFinishedListener";
+
+    /**
      * Descriptions of app transition animations to be played during the activity launch.
      */
     private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";
@@ -198,6 +205,7 @@
     private int mWidth;
     private int mHeight;
     private IRemoteCallback mAnimationStartedListener;
+    private IRemoteCallback mAnimationFinishedListener;
     private ResultReceiver mTransitionReceiver;
     private boolean mIsReturning;
     private ArrayList<String> mSharedElementNames;
@@ -280,16 +288,15 @@
         return opts;
     }
 
-    private void setOnAnimationStartedListener(Handler handler,
-            OnAnimationStartedListener listener) {
+    private void setOnAnimationStartedListener(final Handler handler,
+            final OnAnimationStartedListener listener) {
         if (listener != null) {
-            final Handler h = handler;
-            final OnAnimationStartedListener finalListener = listener;
             mAnimationStartedListener = new IRemoteCallback.Stub() {
-                @Override public void sendResult(Bundle data) throws RemoteException {
-                    h.post(new Runnable() {
+                @Override
+                public void sendResult(Bundle data) throws RemoteException {
+                    handler.post(new Runnable() {
                         @Override public void run() {
-                            finalListener.onAnimationStarted();
+                            listener.onAnimationStarted();
                         }
                     });
                 }
@@ -306,6 +313,32 @@
         void onAnimationStarted();
     }
 
+    private void setOnAnimationFinishedListener(final Handler handler,
+            final OnAnimationFinishedListener listener) {
+        if (listener != null) {
+            mAnimationFinishedListener = new IRemoteCallback.Stub() {
+                @Override
+                public void sendResult(Bundle data) throws RemoteException {
+                    handler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            listener.onAnimationFinished();
+                        }
+                    });
+                }
+            };
+        }
+    }
+
+    /**
+     * Callback for use with {@link ActivityOptions#makeThumbnailAspectScaleDownAnimation}
+     * to find out when the given animation has drawn its last frame.
+     * @hide
+     */
+    public interface OnAnimationFinishedListener {
+        void onAnimationFinished();
+    }
+
     /**
      * Create an ActivityOptions specifying an animation where the new
      * activity is scaled from a small originating area of the screen to
@@ -523,12 +556,14 @@
     /** @hide */
     public static ActivityOptions makeThumbnailAspectScaleDownAnimation(View source,
             AppTransitionAnimationSpec[] specs, Handler handler,
-            OnAnimationStartedListener listener) {
+            OnAnimationStartedListener onAnimationStartedListener,
+            OnAnimationFinishedListener onAnimationFinishedListener) {
         ActivityOptions opts = new ActivityOptions();
         opts.mPackageName = source.getContext().getPackageName();
         opts.mAnimationType = ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
         opts.mAnimSpecs = specs;
-        opts.setOnAnimationStartedListener(handler, listener);
+        opts.setOnAnimationStartedListener(handler, onAnimationStartedListener);
+        opts.setOnAnimationFinishedListener(handler, onAnimationFinishedListener);
         return opts;
     }
 
@@ -725,6 +760,10 @@
                 mAnimSpecs[i] = (AppTransitionAnimationSpec) specs[i];
             }
         }
+        if (opts.containsKey(KEY_ANIMATION_FINISHED_LISTENER)) {
+            mAnimationFinishedListener = IRemoteCallback.Stub.asInterface(
+                    opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER));
+        }
     }
 
     /** @hide */
@@ -800,6 +839,11 @@
     }
 
     /** @hide */
+    public IRemoteCallback getAnimationFinishedListener() {
+        return mAnimationFinishedListener;
+    }
+
+    /** @hide */
     public int getExitCoordinatorKey() { return mExitCoordinatorIndex; }
 
     /** @hide */
@@ -929,6 +973,7 @@
                 break;
         }
         mAnimSpecs = otherOptions.mAnimSpecs;
+        mAnimationFinishedListener = otherOptions.mAnimationFinishedListener;
     }
 
     /**
@@ -998,6 +1043,9 @@
         if (mAnimSpecs != null) {
             b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
         }
+        if (mAnimationFinishedListener != null) {
+            b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder());
+        }
 
         return b;
     }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7adfa8d..f18b35d 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -138,7 +138,7 @@
      * @hide
      */
     void overridePendingAppTransitionMultiThumb(in AppTransitionAnimationSpec[] specs,
-            IRemoteCallback startedCallback, boolean scaleUp);
+            IRemoteCallback startedCallback, IRemoteCallback finishedCallback, boolean scaleUp);
     void overridePendingAppTransitionInPlace(String packageName, int anim);
     void executeAppTransition();
     void setAppStartingWindow(IBinder token, String pkg, int theme,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index dc80259..4d575bc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -32,7 +32,6 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewStub;
@@ -43,6 +42,7 @@
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.activity.IterateRecentsEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -419,6 +419,17 @@
     }
 
     @Override
+    protected void onResume() {
+        super.onResume();
+
+        final RecentsActivityLaunchState state = Recents.getConfiguration().getLaunchState();
+        if (state.startHidden) {
+            state.startHidden = false;
+            mRecentsView.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    @Override
     protected void onPause() {
         super.onPause();
         if (mAfterPauseRunnable != null) {
@@ -645,6 +656,10 @@
         ctx.postAnimationTrigger.decrement();
     }
 
+    public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) {
+        mRecentsView.setVisibility(View.VISIBLE);
+    }
+
     public final void onBusEvent(AppWidgetProviderChangedEvent event) {
         refreshSearchWidgetView();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index aca816e..31ce569 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -35,6 +35,7 @@
     public boolean launchedFromSearchHome;
     public boolean launchedReuseTaskStackViews;
     public boolean launchedHasConfigurationChanged;
+    public boolean startHidden;
     public int launchedToTaskId;
     public int launchedNumVisibleTasks;
     public int launchedNumVisibleThumbnails;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index c314f3f..243c0e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -45,6 +45,7 @@
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.activity.IterateRecentsEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -69,7 +70,7 @@
  * be called remotely from the system user.
  */
 public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
-        implements ActivityOptions.OnAnimationStartedListener {
+        implements ActivityOptions.OnAnimationStartedListener, ActivityOptions.OnAnimationFinishedListener {
 
     private final static String TAG = "RecentsImpl";
     private final static boolean DEBUG = false;
@@ -79,7 +80,6 @@
     public final static String RECENTS_PACKAGE = "com.android.systemui";
     public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
 
-
     /**
      * An implementation of ITaskStackListener, that allows us to listen for changes to the system
      * task stacks and update recents accordingly.
@@ -579,7 +579,7 @@
             AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()];
             specs.toArray(specsArray);
             return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
-                    specsArray, mHandler, this);
+                    specsArray, mHandler, this, this);
         } else {
             // Update the destination rect
             Task toTask = new Task();
@@ -757,6 +757,7 @@
         launchState.launchedNumVisibleTasks = vr.numVisibleTasks;
         launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
         launchState.launchedHasConfigurationChanged = false;
+        launchState.startHidden = topTask != null && topTask.stackId == FREEFORM_WORKSPACE_STACK_ID;
 
         Intent intent = new Intent();
         intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
@@ -781,4 +782,9 @@
             EventBus.getDefault().post(new EnterRecentsWindowAnimationStartedEvent());
         }
     }
+
+    @Override
+    public void onAnimationFinished() {
+        EventBus.getDefault().post(new EnterRecentsWindowLastAnimationFrameEvent());
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowLastAnimationFrameEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowLastAnimationFrameEvent.java
new file mode 100644
index 0000000..fd023d8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowLastAnimationFrameEvent.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+public class EnterRecentsWindowLastAnimationFrameEvent extends EventBus.Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index a8a8259..422e917 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -476,7 +476,7 @@
                 new AppTransitionAnimationSpec[specs.size()];
         try {
             WindowManagerGlobal.getWindowManagerService().overridePendingAppTransitionMultiThumb(
-                    specs.toArray(specsArray), callback, true /* scaleUp */);
+                    specs.toArray(specsArray), callback, null, true /* scaleUp */);
 
         } catch (RemoteException e) {
             Log.w(TAG, "Error overriding app transition", e);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 499aba9..76c4f1e 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -874,7 +874,8 @@
                     if (animationType == ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
                             && specs != null) {
                         service.mWindowManager.overridePendingAppTransitionMultiThumb(
-                                specs, pendingOptions.getOnAnimationStartListener(), false);
+                                specs, pendingOptions.getOnAnimationStartListener(),
+                                pendingOptions.getAnimationFinishedListener(), false);
                     } else {
                         service.mWindowManager.overridePendingAppTransitionAspectScaledThumb(
                                 pendingOptions.getThumbnail(),
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index eb0ca23..468cf6d 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -160,6 +160,7 @@
     // Used for thumbnail transitions. True if we're scaling up, false if scaling down
     private boolean mNextAppTransitionScaleUp;
     private IRemoteCallback mNextAppTransitionCallback;
+    private IRemoteCallback mAnimationFinishedCallback;
     private int mNextAppTransitionEnter;
     private int mNextAppTransitionExit;
     private int mNextAppTransitionInPlace;
@@ -932,6 +933,22 @@
                 : new TranslateAnimation(0, fromX, 0, fromY);
         set.addAnimation(scale);
         set.addAnimation(translation);
+
+        final IRemoteCallback callback = mAnimationFinishedCallback;
+        if (callback != null) {
+            set.setAnimationListener(new Animation.AnimationListener() {
+                @Override
+                public void onAnimationStart(Animation animation) { }
+
+                @Override
+                public void onAnimationEnd(Animation animation) {
+                    mH.obtainMessage(H.DO_ANIMATION_CALLBACK, callback).sendToTarget();
+                }
+
+                @Override
+                public void onAnimationRepeat(Animation animation) { }
+            });
+        }
         return set;
     }
 
@@ -1356,7 +1373,8 @@
     }
 
     public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
-            IRemoteCallback callback, boolean scaleUp) {
+            IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
+            boolean scaleUp) {
         if (isTransitionSet()) {
             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
                     : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
@@ -1378,7 +1396,8 @@
                 }
             }
             postAnimationCallback();
-            mNextAppTransitionCallback = callback;
+            mNextAppTransitionCallback = onAnimationStartedCallback;
+            mAnimationFinishedCallback = onAnimationFinishedCallback;
         } else {
             postAnimationCallback();
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 140fbaf..75680a0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3637,9 +3637,11 @@
 
     @Override
     public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
-            IRemoteCallback callback, boolean scaleUp) {
+            IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
+            boolean scaleUp) {
         synchronized (mWindowMap) {
-            mAppTransition.overridePendingAppTransitionMultiThumb(specs, callback, scaleUp);
+            mAppTransition.overridePendingAppTransitionMultiThumb(specs, onAnimationStartedCallback,
+                    onAnimationFinishedCallback, scaleUp);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 80f1094..aa242f1 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -282,9 +282,8 @@
         }
         mTransformation.clear();
         final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
-        if (false && DEBUG_ANIM) Slog.v(
-            TAG, "Stepped animation in " + this +
-            ": more=" + more + ", xform=" + mTransformation);
+        if (false && DEBUG_ANIM) Slog.v(TAG, "Stepped animation in " + this + ": more=" + more
+                + ", xform=" + mTransformation);
         return more;
     }