Merge "Fix ANR when switching the app task but IME selection dialog focused" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-07-28 11:50:16 +00:00
committed by Android (Google) Code Review
5 changed files with 58 additions and 13 deletions

View File

@@ -116,8 +116,10 @@ public abstract class InputMethodManagerInternal {
*
* @param windowToken the window token that is now in control, or {@code null} if no client
* window is in control of the IME.
* @param imeParentChanged {@code true} when the window manager thoughts the IME surface parent
* will end up to change later, or {@code false} otherwise.
*/
public abstract void reportImeControl(@Nullable IBinder windowToken);
public abstract void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged);
/**
* Destroys the IME surface.
@@ -176,7 +178,8 @@ public abstract class InputMethodManagerInternal {
}
@Override
public void reportImeControl(@Nullable IBinder windowToken) {
public void reportImeControl(@Nullable IBinder windowToken,
boolean imeParentChanged) {
}
@Override

View File

@@ -4937,13 +4937,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken);
}
private void reportImeControl(@Nullable IBinder windowToken) {
private void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
synchronized (mMethodMap) {
if (mCurFocusedWindow != windowToken) {
// mCurPerceptible was set by the focused window, but it is no longer in control,
// so we reset mCurPerceptible.
mCurPerceptible = true;
}
if (imeParentChanged) {
// Hide the IME method menu earlier when the IME surface parent will change in
// case seeing the dialog dismiss flickering during the next focused window
// starting the input connection.
mMenuController.hideInputMethodMenu();
}
}
}
@@ -5001,8 +5007,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
@Override
public void reportImeControl(@Nullable IBinder windowToken) {
mService.reportImeControl(windowToken);
public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
mService.reportImeControl(windowToken, imeParentChanged);
}
@Override

View File

@@ -225,7 +225,8 @@ public final class MultiClientInputMethodManagerService {
}
@Override
public void reportImeControl(@Nullable IBinder windowToken) {
public void reportImeControl(@Nullable IBinder windowToken,
boolean imeParentChanged) {
}
@Override

View File

@@ -729,12 +729,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// When switching the app task, we keep the IME window visibility for better
// transitioning experiences.
// However, in case IME created a child window without dismissing during the task
// switching to keep the window focus because IME window has higher window hierarchy,
// we don't give it focus if the next IME layering target doesn't request IME visible.
if (w.mIsImWindow && w.isChildWindow() && (mImeLayeringTarget == null
// However, in case IME created a child window or the IME selection dialog without
// dismissing during the task switching to keep the window focus because IME window has
// higher window hierarchy, we don't give it focus if the next IME layering target
// doesn't request IME visible.
if (w.mIsImWindow && (mImeLayeringTarget == null
|| !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME))) {
return false;
if (w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
return false;
}
if (w.isChildWindow()) {
return false;
}
}
final ActivityRecord activity = w.mActivityRecord;
@@ -3978,7 +3985,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Update Ime parent when IME insets leash created or the new IME layering target might
// updated from setImeLayeringTarget, which is the best time that default IME visibility
// has been settled down after IME control target changed.
if (prevImeControlTarget != mImeControlTarget || forceUpdateImeParent) {
final boolean imeParentChanged =
prevImeControlTarget != mImeControlTarget || forceUpdateImeParent;
if (imeParentChanged) {
updateImeParent();
}
@@ -3986,7 +3995,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final IBinder token = win != null ? win.mClient.asBinder() : null;
// Note: not allowed to call into IMMS with the WM lock held, hence the post.
mWmService.mH.post(() ->
InputMethodManagerInternal.get().reportImeControl(token)
InputMethodManagerInternal.get().reportImeControl(token, imeParentChanged)
);
}

View File

@@ -50,6 +50,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
@@ -2201,6 +2202,31 @@ public class DisplayContentTests extends WindowTestsBase {
assertNotEquals(imeChildWindow, mDisplayContent.findFocusedWindow());
}
@UseTestDisplay(addWindows = W_INPUT_METHOD)
@Test
public void testImeMenuDialogFocusWhenImeLayeringTargetChanges() {
final WindowState imeMenuDialog =
createWindow(mImeWindow, TYPE_INPUT_METHOD_DIALOG, "imeMenuDialog");
makeWindowVisibleAndDrawn(imeMenuDialog, mImeWindow);
assertTrue(imeMenuDialog.canReceiveKeys());
mDisplayContent.setInputMethodWindowLocked(mImeWindow);
// Verify imeMenuDialog can be focused window if the next IME target requests IME visible.
final WindowState imeAppTarget =
createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
mDisplayContent.setImeLayeringTarget(imeAppTarget);
spyOn(imeAppTarget);
doReturn(true).when(imeAppTarget).getRequestedVisibility(ITYPE_IME);
assertEquals(imeMenuDialog, mDisplayContent.findFocusedWindow());
// Verify imeMenuDialog doesn't be focused window if the next IME target does not
// request IME visible.
final WindowState nextImeAppTarget =
createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "nextImeAppTarget");
mDisplayContent.setImeLayeringTarget(nextImeAppTarget);
assertNotEquals(imeMenuDialog, mDisplayContent.findFocusedWindow());
}
private void removeRootTaskTests(Runnable runnable) {
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,