Add nice animation when adjusting for IME in multi-window

- Run a separate animation when we need to adjust for the IME. We
can't use the attached animation because the adjustment animation
needs to be longer than the IME animation.
- Also run an animation when IME is disappearing.
- Adjust IME exit animation to better match with adjustment exit
animation.
- Make sure to update adjust for IME when entry/exit animation of
IME is starting, to avoid flickers.
- Don't update the IME window in PhoneWindowManager for layout
until the animation has started. This lead to an issue where the
content inset was set too large too early.

Bug: 27154882
Bug: 28175599
Change-Id: I09a33413e307f84d6c3cf4ae928c280f7ad48348
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ff537be..7d76759 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -38,6 +38,7 @@
 import android.view.SurfaceControl;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
 
 import com.android.server.wm.DimLayer.DimLayerUser;
 
@@ -74,6 +75,11 @@
      */
     private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
 
+    private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
+            new PathInterpolator(0.1f, 0f, 0.1f, 1f);
+
+    private static final long IME_ADJUST_DURATION = 280;
+
     private final WindowManagerService mService;
     private final DisplayContent mDisplayContent;
     private int mDividerWindowWidth;
@@ -188,8 +194,10 @@
 
     void setAdjustedForIme(boolean adjusted, boolean animate) {
         if (mAdjustedForIme != adjusted) {
-            mAnimatingForIme = animate;
             mAdjustedForIme = adjusted;
+            if (animate) {
+                startImeAdjustAnimation(adjusted ? 0 : 1, adjusted ? 1 : 0);
+            }
         }
     }
 
@@ -371,7 +379,7 @@
             return;
         }
 
-        mAnimatingForIme = false;
+        clearImeAdjustAnimation();
         if (minimizedDock) {
             if (animate) {
                 startAdjustAnimation(0f, 1f);
@@ -387,6 +395,17 @@
         }
     }
 
+    private void clearImeAdjustAnimation() {
+        final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
+        for (int i = stacks.size() - 1; i >= 0; --i) {
+            final TaskStack stack = stacks.get(i);
+            if (stack != null && stack.isAdjustedForIme()) {
+                stack.resetAdjustedForIme(true /* adjustBoundsNow */);
+            }
+        }
+        mAnimatingForIme = false;
+    }
+
     private void startAdjustAnimation(float from, float to) {
         mAnimatingForMinimizedDockedStack = true;
         mAnimationStarted = false;
@@ -394,6 +413,13 @@
         mAnimationTarget = to;
     }
 
+    private void startImeAdjustAnimation(float from, float to) {
+        mAnimatingForIme = true;
+        mAnimationStarted = false;
+        mAnimationStart = from;
+        mAnimationTarget = to;
+    }
+
     private void setMinimizedDockedStack(boolean minimized) {
         final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
         notifyDockedStackMinimizedChanged(minimized, 0);
@@ -413,39 +439,44 @@
         if (mAnimatingForMinimizedDockedStack) {
             return animateForMinimizedDockedStack(now);
         } else if (mAnimatingForIme) {
-            return animateForIme();
+            return animateForIme(now);
         } else {
             return false;
         }
     }
 
-    private boolean animateForIme() {
-        boolean updated = false;
-        boolean animating = false;
-
+    private boolean animateForIme(long now) {
+        if (!mAnimationStarted) {
+            mAnimationStarted = true;
+            mAnimationStartTime = now;
+            mAnimationDuration = (long)
+                    (IME_ADJUST_DURATION * mService.getWindowAnimationScaleLocked());
+        }
+        float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
+        t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
+                .getInterpolation(t);
         final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
+        boolean updated = false;
         for (int i = stacks.size() - 1; i >= 0; --i) {
             final TaskStack stack = stacks.get(i);
             if (stack != null && stack.isAdjustedForIme()) {
-                updated |= stack.updateAdjustForIme();
-                animating |= stack.isAnimatingForIme();
-            }
-        }
-
-        if (updated) {
-            mService.mWindowPlacerLocked.performSurfacePlacement();
-        }
-
-        if (!animating) {
-            mAnimatingForIme = false;
-            for (int i = stacks.size() - 1; i >= 0; --i) {
-                final TaskStack stack = stacks.get(i);
-                if (stack != null) {
-                    stack.clearImeGoingAway();
+                if (t >= 1f && mAnimationTarget == 0f) {
+                    stack.resetAdjustedForIme(true /* adjustBoundsNow */);
+                    updated = true;
+                } else {
+                    updated |= stack.updateAdjustForIme(getInterpolatedAnimationValue(t));
                 }
             }
         }
-        return animating;
+        if (updated) {
+            mService.mWindowPlacerLocked.performSurfacePlacement();
+        }
+        if (t >= 1.0f) {
+            mAnimatingForIme = false;
+            return false;
+        } else {
+            return true;
+        }
     }
 
     private boolean animateForMinimizedDockedStack(long now) {
@@ -478,11 +509,15 @@
         }
     }
 
+    private float getInterpolatedAnimationValue(float t) {
+        return t * mAnimationTarget + (1 - t) * mAnimationStart;
+    }
+
     /**
      * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
      */
     private float getMinimizeAmount(TaskStack stack, float t) {
-        final float naturalAmount = t * mAnimationTarget + (1 - t) * mAnimationStart;
+        final float naturalAmount = getInterpolatedAnimationValue(t);
         if (isAnimationMaximizing()) {
             return adjustMaximizeAmount(stack, t, naturalAmount);
         } else {