RESTRICT AUTOMERGE: Polish IME transition from fullscreen task to split-screen task
As the new split-screen behavior that the root task of the split-screen can be in the recents task, so using quick switch can switch between the split-screen task and other fullscreen tasks. So if the IME shown on the fullscreen task, when quick switch to the split-screen task, basically the expected result will be IME attached on the fullscreen task then won't expect IME moved to the split-screen task. However, the issue case is that seen the IME flicker on top of the split-screen task and then disappeared. The root case is in DC#computeImeParent didn't consider to not change the new IME surface parent while the next IME input target has not yet updated and settled the new IME visiblity, so IME may flicker if changing the new IME parent too early. (Typically the IME parent will be on the root displayArea when the next target task is in multi-window mode) We do defer changing IME parent from CL[1] when shouldImeAttachedToApp is true, but this check didn't applied when switching to the split-screen task, because shouldImeAttachedToApp will be false when the next IME layering taget is in multi-window mode. Simply move the above defer update IME parent logic out from shouldImeAttachedToApp check to fix this IME flicker issue. Also, remove shouldImeAttachedToApp check in InsetsPolicy#adjustVisibilityForIme when the window is in insets frozen state waiting for the next input started. Since there is no strong reason to froze IME insets only when switching on fullscreen tasks. [1]: I01b67b9a7fdf04f23ab05c244281f42518352ca5 Fix: 210391817 Test: atest DisplayContentTests#testComputeImeParent_inputTargetNotUpdate Test: atest WindowStateTests#\ testAdjustImeInsetsVisibilityWhenSwitchingApps_toAppInMultiWindowMode Change-Id: I332c0e4fff62df5d7b793eda2767bb58fe85a938
This commit is contained in:
@@ -4193,17 +4193,17 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
|||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
SurfaceControl computeImeParent() {
|
SurfaceControl computeImeParent() {
|
||||||
|
if (mImeLayeringTarget != null && mImeInputTarget != null
|
||||||
|
&& mImeLayeringTarget.mActivityRecord != mImeInputTarget.mActivityRecord) {
|
||||||
|
// Do not change parent if the window hasn't requested IME.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
// Attach it to app if the target is part of an app and such app is covering the entire
|
// Attach it to app if the target is part of an app and such app is covering the entire
|
||||||
// screen. If it's not covering the entire screen the IME might extend beyond the apps
|
// screen. If it's not covering the entire screen the IME might extend beyond the apps
|
||||||
// bounds.
|
// bounds.
|
||||||
if (shouldImeAttachedToApp()) {
|
if (shouldImeAttachedToApp()) {
|
||||||
if (mImeLayeringTarget.mActivityRecord != mImeInputTarget.mActivityRecord) {
|
|
||||||
// Do not change parent if the window hasn't requested IME.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return mImeLayeringTarget.mActivityRecord.getSurfaceControl();
|
return mImeLayeringTarget.mActivityRecord.getSurfaceControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we just attach it to where the display area policy put it.
|
// Otherwise, we just attach it to where the display area policy put it.
|
||||||
return mImeWindowsContainer.getParent() != null
|
return mImeWindowsContainer.getParent() != null
|
||||||
? mImeWindowsContainer.getParent().getSurfaceControl() : null;
|
? mImeWindowsContainer.getParent().getSurfaceControl() : null;
|
||||||
|
|||||||
@@ -265,14 +265,12 @@ class InsetsPolicy {
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
} else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
|
} else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
|
||||||
// During switching tasks with gestural navigation, if the IME is attached to
|
// During switching tasks with gestural navigation, before the next IME input target
|
||||||
// one app window on that time, even the next app window is behind the IME window,
|
// starts the input, we should adjust and freeze the last IME visibility of the window
|
||||||
// conceptually the window should not receive the IME insets if the next window is
|
// in case delivering obsoleted IME insets state during transitioning.
|
||||||
// not eligible IME requester and ready to show IME on top of it.
|
|
||||||
final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp();
|
|
||||||
final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME);
|
final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME);
|
||||||
|
|
||||||
if (shouldImeAttachedToApp && originalImeSource != null) {
|
if (originalImeSource != null) {
|
||||||
final boolean imeVisibility =
|
final boolean imeVisibility =
|
||||||
w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME);
|
w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME);
|
||||||
final InsetsState state = copyState ? new InsetsState(originalState)
|
final InsetsState state = copyState ? new InsetsState(originalState)
|
||||||
|
|||||||
@@ -3065,11 +3065,11 @@ public class ActivityRecordTests extends WindowTestsBase {
|
|||||||
|
|
||||||
// Simulate app re-start input or turning screen off/on then unlocked by un-secure
|
// Simulate app re-start input or turning screen off/on then unlocked by un-secure
|
||||||
// keyguard to back to the app, expect IME insets is not frozen
|
// keyguard to back to the app, expect IME insets is not frozen
|
||||||
|
mDisplayContent.updateImeInputAndControlTarget(app);
|
||||||
|
assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
|
||||||
imeSource.setFrame(new Rect(100, 400, 500, 500));
|
imeSource.setFrame(new Rect(100, 400, 500, 500));
|
||||||
app.getInsetsState().addSource(imeSource);
|
app.getInsetsState().addSource(imeSource);
|
||||||
app.getInsetsState().setSourceVisible(ITYPE_IME, true);
|
app.getInsetsState().setSourceVisible(ITYPE_IME, true);
|
||||||
mDisplayContent.updateImeInputAndControlTarget(app);
|
|
||||||
assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
|
|
||||||
|
|
||||||
// Verify when IME is visible and the app can receive the right IME insets from policy.
|
// Verify when IME is visible and the app can receive the right IME insets from policy.
|
||||||
makeWindowVisibleAndDrawn(app, mImeWindow);
|
makeWindowVisibleAndDrawn(app, mImeWindow);
|
||||||
|
|||||||
@@ -1075,6 +1075,21 @@ public class DisplayContentTests extends WindowTestsBase {
|
|||||||
assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
|
assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UseTestDisplay(addWindows = W_ACTIVITY)
|
||||||
|
@Test
|
||||||
|
public void testComputeImeParent_inputTargetNotUpdate() throws Exception {
|
||||||
|
WindowState app1 = createWindow(null, TYPE_BASE_APPLICATION, "app1");
|
||||||
|
WindowState app2 = createWindow(null, TYPE_BASE_APPLICATION, "app2");
|
||||||
|
doReturn(true).when(mDisplayContent).shouldImeAttachedToApp();
|
||||||
|
mDisplayContent.setImeLayeringTarget(app1);
|
||||||
|
mDisplayContent.setImeInputTarget(app1);
|
||||||
|
assertEquals(app1.mActivityRecord.getSurfaceControl(), mDisplayContent.computeImeParent());
|
||||||
|
mDisplayContent.setImeLayeringTarget(app2);
|
||||||
|
// Expect null means no change IME parent when the IME layering target not yet
|
||||||
|
// request IME to be the input target.
|
||||||
|
assertNull(mDisplayContent.computeImeParent());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInputMethodInputTarget_isClearedWhenWindowStateIsRemoved() throws Exception {
|
public void testInputMethodInputTarget_isClearedWhenWindowStateIsRemoved() throws Exception {
|
||||||
final DisplayContent dc = createNewDisplay();
|
final DisplayContent dc = createNewDisplay();
|
||||||
|
|||||||
@@ -927,6 +927,47 @@ public class WindowStateTests extends WindowTestsBase {
|
|||||||
|
|
||||||
@UseTestDisplay(addWindows = { W_ACTIVITY })
|
@UseTestDisplay(addWindows = { W_ACTIVITY })
|
||||||
@Test
|
@Test
|
||||||
|
public void testAdjustImeInsetsVisibilityWhenSwitchingApps_toAppInMultiWindowMode() {
|
||||||
|
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
|
||||||
|
final WindowState app2 = createWindow(null, WINDOWING_MODE_MULTI_WINDOW,
|
||||||
|
ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app2");
|
||||||
|
final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
|
||||||
|
spyOn(imeWindow);
|
||||||
|
doReturn(true).when(imeWindow).isVisible();
|
||||||
|
mDisplayContent.mInputMethodWindow = imeWindow;
|
||||||
|
|
||||||
|
final InsetsStateController controller = mDisplayContent.getInsetsStateController();
|
||||||
|
controller.getImeSourceProvider().setWindow(imeWindow, null, null);
|
||||||
|
|
||||||
|
// Simulate app2 in multi-window mode is going to background to switch to the fullscreen
|
||||||
|
// app which requests IME with updating all windows Insets State when IME is above app.
|
||||||
|
app2.mActivityRecord.mImeInsetsFrozenUntilStartInput = true;
|
||||||
|
mDisplayContent.setImeLayeringTarget(app);
|
||||||
|
mDisplayContent.setImeInputTarget(app);
|
||||||
|
assertTrue(mDisplayContent.shouldImeAttachedToApp());
|
||||||
|
controller.getImeSourceProvider().scheduleShowImePostLayout(app);
|
||||||
|
controller.getImeSourceProvider().getSource().setVisible(true);
|
||||||
|
controller.updateAboveInsetsState(imeWindow, false);
|
||||||
|
|
||||||
|
// Expect app windows behind IME can receive IME insets visible,
|
||||||
|
// but not for app2 in background.
|
||||||
|
assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
|
||||||
|
assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
|
||||||
|
|
||||||
|
// Simulate app plays closing transition to app2.
|
||||||
|
// And app2 is now IME layering target but not yet to be the IME input target.
|
||||||
|
mDisplayContent.setImeLayeringTarget(app2);
|
||||||
|
app.mActivityRecord.commitVisibility(false, false);
|
||||||
|
assertTrue(app.mActivityRecord.mLastImeShown);
|
||||||
|
assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
|
||||||
|
|
||||||
|
// Verify the IME insets is still visible on app, but not for app2 during task switching.
|
||||||
|
assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
|
||||||
|
assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseTestDisplay(addWindows = {W_ACTIVITY})
|
||||||
|
@Test
|
||||||
public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
|
public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
|
||||||
WindowState app = createWindow(null, TYPE_BASE_APPLICATION,
|
WindowState app = createWindow(null, TYPE_BASE_APPLICATION,
|
||||||
mAppWindow.mToken, "app");
|
mAppWindow.mToken, "app");
|
||||||
|
|||||||
Reference in New Issue
Block a user