Fix IME flicker by dispatching unrelated insets after unset IME frozen

CL[1] to add InsetsStateController#updateAboveInsetsState in
DC#updateImeInputAndControlTarget that after setting
mImeInsetsFrozenUntilStartInput as false to unfreeze IME insets,
so that increases the possibility to deliver the last IME insets
change to non-IME input target window that didn't request show IME.
(Since updateImeInputAndControlTarget will call
 WindowState#insetsChanged to client eventually)

As typically the new IME insets change will deliver to the client when
server receives InsetsStateController#onInsetsModified(InsetsControlTarget)
from the client requests IME visible after
DC#updateImeInputAndControlTarget.

So in DC#updateImeInputAndControlTarget, we should ensure to unfreeze
IME insets after the input target updated, in case updateAboveInsetsState
may deliver unrelated IME insets change to the non-IME requester.

[1]: I57357ba85501397fa5926ab4dee116c42df24506

Bug: 213522825
Test: atest ActivityRecordTests#\
       testImeInsetsFrozenFlag_noDispatchVisibleInsetsWhenAppNotRequest
Test: atest WindowStateTests#\
        testAdjustImeInsetsVisibilityWhenSwitchingApps
Test: Verify Bug 195385541 and Bug 195846009 that keyboard
      won't cover the edit text.

(cherry picked from commit 938eb8fd2ded04bbcd5f32576a7bb4eaf186d56a)
(cherry picked from commit be42921e05ba3d1946efc090054cd4a498f22b80)
Merged-In: I95c5b45bd4cf9c30ff7771b2db485c8ae2b0c6db
Change-Id: I95c5b45bd4cf9c30ff7771b2db485c8ae2b0c6db
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1e31fda..42c6dd4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4122,9 +4122,6 @@
      * which controls the visibility and animation of the input method window.
      */
     void updateImeInputAndControlTarget(WindowState target) {
-        if (target != null && target.mActivityRecord != null) {
-            target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false;
-        }
         if (mImeInputTarget != target) {
             ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target);
             setImeInputTarget(target);
@@ -4132,6 +4129,11 @@
                     .getRawInsetsState().getSourceOrDefaultVisibility(ITYPE_IME));
             updateImeControlTarget();
         }
+        // Unfreeze IME insets after the new target updated, in case updateAboveInsetsState may
+        // deliver unrelated IME insets change to the non-IME requester.
+        if (target != null && target.mActivityRecord != null) {
+            target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false;
+        }
     }
 
     void updateImeControlTarget() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 9a68b5f..dd4cc50 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -99,6 +99,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.never;
 
@@ -131,6 +132,7 @@
 import android.view.IWindowSession;
 import android.view.InsetsSource;
 import android.view.InsetsState;
+import android.view.InsetsVisibilities;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
 import android.view.Surface;
@@ -147,6 +149,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.invocation.InvocationOnMock;
 
 import java.util.ArrayList;
@@ -3076,6 +3079,50 @@
         assertEquals(state.getSource(ITYPE_IME).getFrame(), imeSource.getFrame());
     }
 
+    @UseTestDisplay(addWindows = {W_ACTIVITY, W_INPUT_METHOD})
+    @Test
+    public void testImeInsetsFrozenFlag_noDispatchVisibleInsetsWhenAppNotRequest()
+            throws RemoteException {
+        final WindowState app1 = createWindow(null, TYPE_APPLICATION, "app1");
+        final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
+
+        mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_IME).setWindow(
+                mImeWindow, null, null);
+        mImeWindow.getControllableInsetProvider().setServerVisible(true);
+
+        // Simulate app2 is closing and let app1 is visible to be IME targets.
+        makeWindowVisibleAndDrawn(app1, mImeWindow);
+        mDisplayContent.setImeLayeringTarget(app1);
+        mDisplayContent.updateImeInputAndControlTarget(app1);
+        app2.mActivityRecord.commitVisibility(false, false);
+
+        // app1 requests IME visible.
+        final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+        requestedVisibilities.setVisibility(ITYPE_IME, true);
+        app1.setRequestedVisibilities(requestedVisibilities);
+        mDisplayContent.getInsetsStateController().onInsetsModified(app1);
+
+        // Verify app1's IME insets is visible and app2's IME insets frozen flag set.
+        assertTrue(app1.getInsetsState().peekSource(ITYPE_IME).isVisible());
+        assertTrue(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+        // Simulate switching to app2 to make it visible to be IME targets.
+        makeWindowVisibleAndDrawn(app2);
+        spyOn(app2);
+        spyOn(app2.mClient);
+        ArgumentCaptor<InsetsState> insetsStateCaptor = ArgumentCaptor.forClass(InsetsState.class);
+        doReturn(true).when(app2).isReadyToDispatchInsetsState();
+        mDisplayContent.setImeLayeringTarget(app2);
+        mDisplayContent.updateImeInputAndControlTarget(app2);
+
+        // Verify after unfreezing app2's IME insets state, we won't dispatch visible IME insets
+        // to client if the app didn't request IME visible.
+        assertFalse(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+        verify(app2.mClient, atLeastOnce()).insetsChanged(insetsStateCaptor.capture(), anyBoolean(),
+                anyBoolean());
+        assertFalse(insetsStateCaptor.getAllValues().get(0).peekSource(ITYPE_IME).isVisible());
+    }
+
     @Test
     public void testInClosingAnimation_doNotHideSurface() {
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");