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 * @param windowToken the window token that is now in control, or {@code null} if no client
* window is in control of the IME. * 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. * Destroys the IME surface.
@@ -176,7 +178,8 @@ public abstract class InputMethodManagerInternal {
} }
@Override @Override
public void reportImeControl(@Nullable IBinder windowToken) { public void reportImeControl(@Nullable IBinder windowToken,
boolean imeParentChanged) {
} }
@Override @Override

View File

@@ -4937,13 +4937,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken); return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken);
} }
private void reportImeControl(@Nullable IBinder windowToken) { private void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
synchronized (mMethodMap) { synchronized (mMethodMap) {
if (mCurFocusedWindow != windowToken) { if (mCurFocusedWindow != windowToken) {
// mCurPerceptible was set by the focused window, but it is no longer in control, // mCurPerceptible was set by the focused window, but it is no longer in control,
// so we reset mCurPerceptible. // so we reset mCurPerceptible.
mCurPerceptible = true; 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 @Override
public void reportImeControl(@Nullable IBinder windowToken) { public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
mService.reportImeControl(windowToken); mService.reportImeControl(windowToken, imeParentChanged);
} }
@Override @Override

View File

@@ -225,7 +225,8 @@ public final class MultiClientInputMethodManagerService {
} }
@Override @Override
public void reportImeControl(@Nullable IBinder windowToken) { public void reportImeControl(@Nullable IBinder windowToken,
boolean imeParentChanged) {
} }
@Override @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 // When switching the app task, we keep the IME window visibility for better
// transitioning experiences. // transitioning experiences.
// However, in case IME created a child window without dismissing during the task // However, in case IME created a child window or the IME selection dialog without
// switching to keep the window focus because IME window has higher window hierarchy, // dismissing during the task switching to keep the window focus because IME window has
// we don't give it focus if the next IME layering target doesn't request IME visible. // higher window hierarchy, we don't give it focus if the next IME layering target
if (w.mIsImWindow && w.isChildWindow() && (mImeLayeringTarget == null // doesn't request IME visible.
if (w.mIsImWindow && (mImeLayeringTarget == null
|| !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME))) { || !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; 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 // 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 // updated from setImeLayeringTarget, which is the best time that default IME visibility
// has been settled down after IME control target changed. // has been settled down after IME control target changed.
if (prevImeControlTarget != mImeControlTarget || forceUpdateImeParent) { final boolean imeParentChanged =
prevImeControlTarget != mImeControlTarget || forceUpdateImeParent;
if (imeParentChanged) {
updateImeParent(); updateImeParent();
} }
@@ -3986,7 +3995,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final IBinder token = win != null ? win.mClient.asBinder() : null; final IBinder token = win != null ? win.mClient.asBinder() : null;
// Note: not allowed to call into IMMS with the WM lock held, hence the post. // Note: not allowed to call into IMMS with the WM lock held, hence the post.
mWmService.mH.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_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 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_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_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT; import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
@@ -2201,6 +2202,31 @@ public class DisplayContentTests extends WindowTestsBase {
assertNotEquals(imeChildWindow, mDisplayContent.findFocusedWindow()); 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) { private void removeRootTaskTests(Runnable runnable) {
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,