summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMing-Shin Lu <lumark@google.com>2022-01-19 00:54:21 +0800
committerXin Li <delphij@google.com>2022-03-02 18:17:48 -0800
commit83c396e9e7fd9a94ee410cae1f8a5fe21dbaa96b (patch)
tree64bcf59a1a90a02446b4d1b8f46a9e0ae454fbc5
parentade248a9bc7797209838d3d780f2ee03cff84d64 (diff)
downloadbase-83c396e9e7fd9a94ee410cae1f8a5fe21dbaa96b.tar.gz
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
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java47
2 files changed, 52 insertions, 3 deletions
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1e31fdab30d0..42c6dd43ebce 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 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* 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 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
.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 9a68b5f1b609..dd4cc5022cd2 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.junit.Assert.assertTrue;
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.IWindowManager;
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.Assert;
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 @@ public class ActivityRecordTests extends WindowTestsBase {
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");