Merge "Prevent changing mFromState during insets resize animation" into main
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 1626924..8d884f2 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -713,11 +713,13 @@
             new InsetsState.OnTraverseCallbacks() {
 
                 private @InsetsType int mTypes;
+                private InsetsState mFromState;
                 private InsetsState mToState;
 
                 @Override
                 public void onStart(InsetsState state1, InsetsState state2) {
                     mTypes = 0;
+                    mFromState = null;
                     mToState = null;
                 }
 
@@ -734,9 +736,13 @@
                         return;
                     }
                     mTypes |= source1.getType();
+                    if (mFromState == null) {
+                        mFromState = new InsetsState();
+                    }
                     if (mToState == null) {
                         mToState = new InsetsState();
                     }
+                    mFromState.addSource(new InsetsSource(source1));
                     mToState.addSource(new InsetsSource(source2));
                 }
 
@@ -747,7 +753,7 @@
                     }
                     cancelExistingControllers(mTypes);
                     final InsetsAnimationControlRunner runner = new InsetsResizeAnimationRunner(
-                            mFrame, state1, mToState, RESIZE_INTERPOLATOR,
+                            mFrame, mFromState, mToState, RESIZE_INTERPOLATOR,
                             ANIMATION_DURATION_RESIZE, mTypes, InsetsController.this);
                     if (mRunningAnimations.isEmpty()) {
                         mHost.notifyAnimationRunningStateChanged(true);
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index f05390d..ae7f465 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -32,6 +32,7 @@
 import static android.view.WindowInsets.Type.navigationBars;
 import static android.view.WindowInsets.Type.statusBars;
 import static android.view.WindowInsets.Type.systemBars;
+import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
@@ -52,6 +53,9 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.annotation.NonNull;
 import android.content.Context;
 import android.graphics.Insets;
 import android.graphics.Point;
@@ -80,6 +84,8 @@
 import org.mockito.InOrder;
 import org.mockito.Mockito;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 
 /**
@@ -668,30 +674,58 @@
     }
 
     @Test
-    public void testResizeAnimation_withFlagAnimateResizing() {
+    public void testResizeAnimation_withFlagAnimateResizing() throws InterruptedException {
+        final int id = ID_NAVIGATION_BAR;
+        final @InsetsType int type = navigationBars();
+        final int fromInsetsHeight = 50;
+        final int toInsetsHeight = 60;
+        final ArrayList<WindowInsets> progressList = new ArrayList<>();
+        final CountDownLatch animationEndLatch = new CountDownLatch(1);
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
-            final int id = ID_NAVIGATION_BAR;
-            final @InsetsType int type = navigationBars();
             final InsetsState state1 = new InsetsState();
             state1.getOrCreateSource(id, type)
                     .setVisible(true)
-                    .setFrame(0, 0, 500, 50)
+                    .setFrame(0, 0, 500, fromInsetsHeight)
                     .setFlags(FLAG_ANIMATE_RESIZING, FLAG_ANIMATE_RESIZING);
             final InsetsState state2 = new InsetsState(state1, true /* copySources */);
-            state2.peekSource(id).setFrame(0, 0, 500, 60);
+            state2.peekSource(id).setFrame(0, 0, 500, toInsetsHeight);
 
             // New insets source won't cause the resize animation.
             mController.onStateChanged(state1);
             assertEquals("There must not be resize animation.", ANIMATION_TYPE_NONE,
                     mController.getAnimationType(type));
 
+            mViewRoot.getView().setWindowInsetsAnimationCallback(
+                    new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
+                        @Override
+                        public WindowInsets onProgress(
+                                @NonNull WindowInsets insets,
+                                @NonNull List<WindowInsetsAnimation> runningAnimations) {
+                            progressList.add(insets);
+                            return insets;
+                        }
+
+                        @Override
+                        public void onEnd(@NonNull WindowInsetsAnimation animation) {
+                            animationEndLatch.countDown();
+                        }
+                    });
+
             // Changing frame of the source with FLAG_ANIMATE_RESIZING will cause the resize
             // animation.
             mController.onStateChanged(state2);
             assertEquals("There must be resize animation.", ANIMATION_TYPE_RESIZE,
                     mController.getAnimationType(type));
+
+            mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
         });
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        assertTrue("Animation must be ended.", animationEndLatch.await(3, SECONDS));
+        assertEquals("The first insets height must be the same as `fromInsetsHeight`",
+                fromInsetsHeight, progressList.get(0).getInsets(type).top);
+        assertEquals("The last insets height must be the same as `toInsetsHeight`",
+                toInsetsHeight, progressList.get(progressList.size() - 1).getInsets(type).top);
     }
 
     @Test