diff options
6 files changed, 126 insertions, 31 deletions
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index c50048eeab64..04fc1d2f202b 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -122,6 +122,7 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON; +import static com.android.server.wm.ProtoLogGroup.WM_ERROR; import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.RootWindowContainer.TAG_STATES; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; @@ -3407,6 +3408,57 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo && mInputMethodTarget.mActivityRecord.matchParentBounds()); } + /** + * Get IME target that should host IME when this display that is reparented to another + * WindowState. + * IME is never displayed in a child display. + * Use {@link WindowState#getImeControlTarget()} when IME target window + * which originally called + * {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} is known. + * + * @return {@link WindowState} of host that controls IME. + * {@code null} when {@param dc} is not a virtual display. + * @see DisplayContent#reparent + */ + @Nullable + WindowState getImeControlTarget() { + WindowState imeTarget = mInputMethodTarget; + if (imeTarget != null) { + return imeTarget.getImeControlTarget(); + } + + return getInsetsStateController().getImeSourceProvider().getControlTarget().getWindow(); + } + + /** + * Finds the window which can host IME if IME target cannot host it. + * e.g. IME target cannot host IME when it's display has a parent display OR when display + * doesn't support IME/system decorations. + * + * @param target current IME target. + * @return {@link WindowState} that can host IME. + * @see DisplayContent#getImeControlTarget() + */ + WindowState getImeHostOrFallback(WindowState target) { + if (target != null && target.getDisplayContent().canShowIme()) { + return target; + } + + // host is in non-default display that doesn't support system decor, default to + // default display's StatusBar to control IME. + // TODO: (b/148234093)find a better host OR control IME animation/visibility directly + // because it won't work when statusbar isn't available. + return mWmService.getDefaultDisplayContentLocked().getDisplayPolicy().getStatusBar(); + } + + boolean canShowIme() { + if (isUntrustedVirtualDisplay()) { + return false; + } + return mWmService.mDisplayWindowSettings.shouldShowImeLocked(this) + || mWmService.mForceDesktopModeOnExternalDisplays; + } + private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim) { if (target == mInputMethodTarget && mInputMethodTargetWaitingAnim == targetWaitingAnim) { return; diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java index 154cde140810..20e8f2ba485a 100644 --- a/services/core/java/com/android/server/wm/InsetsControlTarget.java +++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java @@ -26,6 +26,13 @@ interface InsetsControlTarget { void notifyInsetsControlChanged(); /** + * @return {@link WindowState} of this target, if any. + */ + default WindowState getWindow() { + return null; + } + + /** * Instructs the control target to show inset sources. * * @param types to specify which types of insets source window should be shown. diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 2bb58ddc5b38..74f6b387f5eb 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -209,6 +209,12 @@ class InsetsSourceProvider { // to control the window for now. return; } + if (target != null && target.getWindow() != null) { + // ime control target could be a different window. + // Refer WindowState#getImeControlTarget(). + target = target.getWindow().getImeControlTarget(); + } + if (mWin == null) { mControlTarget = target; return; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 2c6c756dda3b..f15e9eb80403 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6991,8 +6991,15 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission"); } boolean show; + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc == null) { + ProtoLog.w(WM_ERROR, + "Attempted to get IME flag of a display that does not exist: %d", + displayId); + return false; + } synchronized (mGlobalLock) { - show = shouldShowImeSystemWindowUncheckedLocked(displayId); + show = dc.canShowIme(); } return show; @@ -7405,15 +7412,13 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void showImePostLayout(IBinder imeTargetWindowToken) { synchronized (mGlobalLock) { - final WindowState imeTarget = mWindowMap.get(imeTargetWindowToken); + WindowState imeTarget = mWindowMap.get(imeTargetWindowToken); if (imeTarget == null) { return; } - final int displayId = imeTarget.getDisplayId(); - if (!shouldShowImeSystemWindowUncheckedLocked(displayId)) { - return; - } + imeTarget = imeTarget.getImeControlTarget(); + final int displayId = imeTarget.getDisplayId(); mRoot.getDisplayContent(displayId).getInsetsStateController().getImeSourceProvider() .scheduleShowImePostLayout(imeTarget); } @@ -7423,12 +7428,16 @@ public class WindowManagerService extends IWindowManager.Stub public void hideIme(int displayId) { synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); - if (dc != null && dc.mInputMethodTarget != null) { + if (dc != null) { + WindowState imeTarget = dc.getImeControlTarget(); + if (imeTarget == null) { + return; + } // If there was a pending IME show(), reset it as IME has been // requested to be hidden. - dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout(); - dc.mInputMethodControlTarget.hideInsets(WindowInsets.Type.ime(), - true /* fromIme */); + imeTarget.getDisplayContent().getInsetsStateController().getImeSourceProvider() + .abortShowImePostLayout(); + imeTarget.hideInsets(WindowInsets.Type.ime(), true /* fromIme */); } } } @@ -7936,21 +7945,6 @@ public class WindowManagerService extends IWindowManager.Stub return true; } - private boolean shouldShowImeSystemWindowUncheckedLocked(final int displayId) { - final DisplayContent displayContent = mRoot.getDisplayContent(displayId); - if (displayContent == null) { - ProtoLog.w(WM_ERROR, - "Attempted to get IME flag of a display that does not exist: %d", - displayId); - return false; - } - if (displayContent.isUntrustedVirtualDisplay()) { - return false; - } - return mDisplayWindowSettings.shouldShowImeLocked(displayContent) - || mForceDesktopModeOnExternalDisplays; - } - @Override public void getWindowInsets(WindowManager.LayoutParams attrs, int displayId, Rect outContentInsets, Rect outStableInsets, diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 874a25e50ae6..47d808e6f045 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3518,6 +3518,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } @Override + public WindowState getWindow() { + return this; + } + + @Override public void showInsets(@InsetsType int types, boolean fromIme) { try { mClient.showInsets(types, fromIme); @@ -5334,6 +5339,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return false; } + /** + * Get IME target that should host IME when this window's display has a parent. + * Note: IME is never hosted by a display that has a parent. + * When window calling + * {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} is unknown, + * use {@link DisplayContent#getImeControlTarget()} instead. + * + * @return {@link WindowState} of host that controls the IME. + * When window is doesn't have a parent, it is returned as-is. + */ + WindowState getImeControlTarget() { + final DisplayContent dc = getDisplayContent(); + final WindowState parentWindow = dc.getParentWindow(); + + // If target's display has a parent, IME is displayed in the parent display. + return dc.getImeHostOrFallback(parentWindow != null ? parentWindow : this); + } + @Override void assignLayer(Transaction t, int layer) { // See comment in assignRelativeLayerForImeTargetChild diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 20eab5a45ff1..8e362ae4c59a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -110,7 +110,7 @@ class WindowTestsBase extends SystemServiceTestsBase { beforeCreateDisplay(); context.getDisplay().getDisplayInfo(mDisplayInfo); - mDisplayContent = createNewDisplay(); + mDisplayContent = createNewDisplay(true /* supportIme */); // Set-up some common windows. mCommonWindows = new HashSet<>(); @@ -349,16 +349,29 @@ class WindowTestsBase extends SystemServiceTestsBase { return WindowTestUtils.createTaskInStack(mWm, stack, userId); } - /** Creates a {@link DisplayContent} and adds it to the system. */ + /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */ DisplayContent createNewDisplay() { - return createNewDisplay(mDisplayInfo); + return createNewDisplay(true /* supportIme */); } /** Creates a {@link DisplayContent} and adds it to the system. */ + private DisplayContent createNewDisplay(boolean supportIme) { + return createNewDisplay(mDisplayInfo, supportIme); + } + + /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */ DisplayContent createNewDisplay(DisplayInfo info) { + return createNewDisplay(info, true /* supportIme */); + } + + /** Creates a {@link DisplayContent} and adds it to the system. */ + private DisplayContent createNewDisplay(DisplayInfo info, boolean supportIme) { final DisplayContent display = new TestDisplayContent.Builder(mWm.mAtmService, info).build(); - return display.mDisplayContent; + final DisplayContent dc = display.mDisplayContent; + // this display can show IME. + dc.mWmService.mDisplayWindowSettings.setShouldShowImeLocked(dc, supportIme); + return dc; } /** @@ -372,7 +385,7 @@ class WindowTestsBase extends SystemServiceTestsBase { DisplayInfo displayInfo = new DisplayInfo(); displayInfo.copyFrom(mDisplayInfo); displayInfo.state = displayState; - return createNewDisplay(displayInfo); + return createNewDisplay(displayInfo, true /* supportIme */); } /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */ @@ -389,7 +402,7 @@ class WindowTestsBase extends SystemServiceTestsBase { displayInfo.copyFrom(mDisplayInfo); displayInfo.type = Display.TYPE_VIRTUAL; displayInfo.ownerUid = SYSTEM_UID; - return createNewDisplay(displayInfo); + return createNewDisplay(displayInfo, false /* supportIme */); } /** Sets the default minimum task size to 1 so that tests can use small task sizes */ |