Improve maximizing dock/clip reveal animation

There was a very visible hole at the end of the transition when both
the docked stack expands and the other app is doing a clip reveal
animation, but only if the app had to travel a far distance to
meet it's target rectangle.

To fix this, we interpolate between two animation curves for maximizing
divider: One is the original curve, and the other one is an adjusted
one which simulate if the divider would start at the edge of the app
surface that plays the clip reveal animation. At the start of the
animation, we use the original curve, but then about in the middle of
the animation we interpolated towards the adjusted curve, so the divider
meets the edge of the app surface that plays the clip reveal animation,
eliminating that gap while still preserving the overall motion.

Bug: 27154882
Change-Id: I37716588f88ddc643ed6176c2ccd56ca174e8919
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index ba9e640..5cb7099 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -216,6 +216,9 @@
     private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
     private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
 
+    private int mLastClipRevealMaxTranslation;
+    private boolean mLastHadClipReveal;
+
     AppTransition(Context context, WindowManagerService service) {
         mContext = context;
         mService = service;
@@ -337,6 +340,9 @@
         if (!isRunning()) {
             mAppTransitionState = APP_STATE_IDLE;
             notifyAppTransitionPendingLocked();
+            mLastHadClipReveal = false;
+            mLastClipRevealMaxTranslation = 0;
+            mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
             return true;
         }
         return false;
@@ -641,11 +647,28 @@
                 bitmap, new Rect(left, top, left + width, top + height));
     }
 
+    /**
+     * @return the duration of the last clip reveal animation
+     */
     long getLastClipRevealTransitionDuration() {
         return mLastClipRevealTransitionDuration;
     }
 
     /**
+     * @return the maximum distance the app surface is traveling of the last clip reveal animation
+     */
+    int getLastClipRevealMaxTranslation() {
+        return mLastClipRevealMaxTranslation;
+    }
+
+    /**
+     * @return true if in the last app transition had a clip reveal animation, false otherwise
+     */
+    boolean hadClipRevealAnimation() {
+        return mLastHadClipReveal;
+    }
+
+    /**
      * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that
      * the start rect is outside of the target rect, and there is a lot of movement going on.
      *
@@ -748,7 +771,13 @@
             set.setZAdjustment(Animation.ZORDER_TOP);
             set.initialize(appWidth, appHeight, appWidth, appHeight);
             anim = set;
+            mLastHadClipReveal = true;
             mLastClipRevealTransitionDuration = duration;
+
+            // If the start rect was full inside the target rect (cutOff == false), we don't need
+            // to store the translation, because it's only used if cutOff == true.
+            mLastClipRevealMaxTranslation = cutOff
+                    ? Math.max(Math.abs(translationY), Math.abs(translationX)) : 0;
         } else {
             final long duration;
             switch (transit) {