Entry animation for docking windows.

We achieve the animation in the same way we would do that for maximizing
windows. We preserve the exiting window of relaunched activity until the
activity adds a new one. Then we animation the new window from the
bounds of the old window to the dock bounds.

This mostly reuses existing infrastructure for maximize animations, but
unfortunately needs scaling. The before window might be have one
dimension larger than after window and using cropping is not sufficient.

Change-Id: I9538ba983a0af1e64ea48aad6836173d6fd25f3b
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 192b168..a64cda6 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1003,17 +1003,33 @@
         return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
     }
 
-    private Animation createRelaunchAnimation(int appWidth, int appHeight) {
+    private Animation createRelaunchAnimation(int appWidth, int appHeight,
+            Rect containingFrame) {
         getDefaultNextAppTransitionStartRect(mTmpFromClipRect);
         final int left = mTmpFromClipRect.left;
         final int top = mTmpFromClipRect.top;
         mTmpFromClipRect.offset(-left, -top);
         mTmpToClipRect.set(0, 0, appWidth, appHeight);
         AnimationSet set = new AnimationSet(true);
-        ClipRectAnimation clip = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
-        TranslateAnimation translate = new TranslateAnimation(left, 0, top, 0);
-        clip.setInterpolator(mDecelerateInterpolator);
-        set.addAnimation(clip);
+        float fromWidth = mTmpFromClipRect.width();
+        float toWidth = mTmpToClipRect.width();
+        float fromHeight = mTmpFromClipRect.height();
+        float toHeight = mTmpToClipRect.height();
+        if (fromWidth <= toWidth && fromHeight <= toHeight) {
+            // The final window is larger in both dimensions than current window (e.g. we are
+            // maximizing), so we can simply unclip the new window and there will be no disappearing
+            // frame.
+            set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect));
+        } else {
+            // The disappearing window has one larger dimension. We need to apply scaling, so the
+            // first frame of the entry animation matches the old window.
+            set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1));
+        }
+
+        // We might not be going exactly full screen, but instead be aligned under the status bar.
+        // We need to take this into account when creating the translate animation.
+        TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left,
+                0, top - containingFrame.top, 0);
         set.addAnimation(translate);
         set.setDuration(DEFAULT_APP_TRANSITION_DURATION);
         return set;
@@ -1056,7 +1072,12 @@
                     + " anim=" + a + " transit=" + appTransitionToString(transit)
                     + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
         } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
-            a = createRelaunchAnimation(appWidth, appHeight);
+            a = createRelaunchAnimation(appWidth, appHeight, containingFrame);
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
+                    "applyAnimation:"
+                    + " anim=" + a + " nextAppTransition=" + mNextAppTransition
+                    + " transit=" + appTransitionToString(transit)
+                    + " Callers=" + Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
             a = loadAnimationRes(mNextAppTransitionPackage, enter ?
                     mNextAppTransitionEnter : mNextAppTransitionExit);
@@ -1077,6 +1098,7 @@
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                     "applyAnimation:"
                             + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
+                            + " transit=" + appTransitionToString(transit)
                             + " Callers=" + Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
             a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight);