Loading services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +2 −6 Original line number Diff line number Diff line Loading @@ -192,7 +192,6 @@ import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeS import com.android.server.pm.UserManagerInternal; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.utils.PriorityDump; import com.android.server.wm.ImeTargetVisibilityPolicy; import com.android.server.wm.WindowManagerInternal; import java.io.FileDescriptor; Loading Loading @@ -409,8 +408,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. @MultiUserUnawareField private final InputMethodMenuController mMenuController; private final InputMethodMenuControllerNew mMenuControllerNew; @NonNull private final ImeTargetVisibilityPolicy mImeTargetVisibilityPolicy; /** * Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}. Loading Loading @@ -1217,7 +1214,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. mImePlatformCompatUtils = new ImePlatformCompatUtils(); mInputMethodDeviceConfigs = new InputMethodDeviceConfigs(); mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mImeTargetVisibilityPolicy = LocalServices.getService(ImeTargetVisibilityPolicy.class); mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime); Loading Loading @@ -5395,7 +5391,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. @VisibleForTesting @GuardedBy("ImfLock.class") void showImeScreenshot(IBinder imeTarget, int displayId, @UserIdInt int userId) { if (mImeTargetVisibilityPolicy.showImeScreenshot(imeTarget, displayId)) { if (mWindowManagerInternal.showImeScreenshot(imeTarget, displayId)) { onShowHideSoftInputRequested(false /* show */, imeTarget, SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS, null /* statsToken */, userId); Loading @@ -5412,7 +5408,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. @VisibleForTesting @GuardedBy("ImfLock.class") void removeImeScreenshot(IBinder imeTarget, int displayId, @UserIdInt int userId) { if (mImeTargetVisibilityPolicy.removeImeScreenshot(displayId)) { if (mWindowManagerInternal.removeImeScreenshot(displayId)) { onShowHideSoftInputRequested(false /* show */, imeTarget, SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS, null /* statsToken */, userId); Loading services/core/java/com/android/server/wm/DisplayContent.java +81 −1 Original line number Diff line number Diff line Loading @@ -4902,7 +4902,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @VisibleForTesting @Nullable WindowContainer computeImeParent() { if (!ImeTargetVisibilityPolicy.canComputeImeParent(mImeLayeringTarget, mImeInputTarget)) { if (!canComputeImeParent(mImeLayeringTarget, mImeInputTarget)) { return null; } // Attach it to app if the IME layering target is part of an app that is covering the entire Loading @@ -4915,6 +4915,86 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return mImeWindowsContainer.getParent(); } /** * Called from {@link #computeImeParent()} to check if we can compute the new IME parent * based on the given IME layering and IME input target. * * @param imeLayeringTarget The window the IME is on top of. * @param imeInputTarget The target which receives input from the IME. * @return {@code true} to keep computing the IME parent, {@code false} to defer this operation. */ private static boolean canComputeImeParent(@Nullable WindowState imeLayeringTarget, @Nullable InputTarget imeInputTarget) { if (imeLayeringTarget == null) { return false; } if (shouldComputeImeParentForEmbeddedActivity(imeLayeringTarget, imeInputTarget)) { return true; } // Ensure changing the IME parent when the layering target that may use IME has // became to the input target for preventing IME flickers. // Note that: // 1) For the imeLayeringTarget that may not use IME but requires IME on top // of it (e.g. an overlay window with NOT_FOCUSABLE|ALT_FOCUSABLE_IM flags), we allow // it to re-parent the IME on top the display to keep the legacy behavior. // 2) Even though the starting window won't use IME, the associated activity // behind the starting window may request the input. If so, then we should still hold // the IME parent change until the activity started the input. boolean imeLayeringTargetMayUseIme = WindowManager.LayoutParams.mayUseInputMethod(imeLayeringTarget.mAttrs.flags) || imeLayeringTarget.mAttrs.type == TYPE_APPLICATION_STARTING; // Do not change parent if the window hasn't requested IME. boolean inputAndLayeringTargetsDisagree = (imeInputTarget == null || imeLayeringTarget.mActivityRecord != imeInputTarget.getActivityRecord()); boolean inputTargetStale = imeLayeringTargetMayUseIme && inputAndLayeringTargetsDisagree; return !inputTargetStale; } /** * Called from {@link #computeImeParent()} to check if the IME surface parent should be * updated in ActivityEmbeddings, based on the given IME layering and IME input target. * * <p>As the IME layering target is calculated according to the window hierarchy by * {@link #computeImeLayeringTarget}, the layering target and input target may be different * when the window hasn't started input connection, WindowManagerService hasn't yet received * the input target which reported from InputMethodManagerService. To make sure the IME * surface will be shown on the best fit IME layering target, we basically won't update IME * parent until both IME layering and input target are updated, for better IME transition. * * <p>However, in activity embedding, tapping a window won't update it to the top window so the * IME layering target may be higher than input target. Update IME parent in this case. * * @param imeLayeringTarget The window the IME is on top of. * @param imeInputTarget The target which receives input from the IME. * * @return {@code true} means the layer of IME layering target is higher than the input target * and {@link #computeImeParent()} should keep progressing to update the IME surface parent * on the display in case the IME surface was left behind. */ private static boolean shouldComputeImeParentForEmbeddedActivity( @Nullable WindowState imeLayeringTarget, @Nullable InputTarget imeInputTarget) { if (imeInputTarget == null || imeLayeringTarget == null) { return false; } final WindowState inputTargetWindow = imeInputTarget.getWindowState(); if (inputTargetWindow == null || !imeLayeringTarget.isAttached() || !inputTargetWindow.isAttached()) { return false; } final ActivityRecord inputTargetRecord = imeInputTarget.getActivityRecord(); final ActivityRecord layeringTargetRecord = imeLayeringTarget.getActivityRecord(); if (inputTargetRecord == null || layeringTargetRecord == null || inputTargetRecord == layeringTargetRecord || (inputTargetRecord.getTask() != layeringTargetRecord.getTask()) || !inputTargetRecord.isEmbedded() || !layeringTargetRecord.isEmbedded()) { // Check whether the input target and layering target are embedded in the same Task. return false; } return imeLayeringTarget.compareTo(inputTargetWindow) > 0; } void setLayoutNeeded() { if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3)); mLayoutNeeded = true; Loading services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.javadeleted 100644 → 0 +0 −131 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IBinder; import android.view.WindowManager; /** * A class for {@link com.android.server.inputmethod.InputMethodManagerService} to * control IME visibility operations in {@link WindowManagerService}. */ public abstract class ImeTargetVisibilityPolicy { /** * Shows the IME screenshot and attaches it to the given IME target window. * * @param imeTarget the token of the IME target window. * @param displayId the ID of the display to show the screenshot on. * @return {@code true} if successful, {@code false} otherwise. */ public abstract boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId); /** * Removes the IME screenshot from the given display. * * @param displayId The target display of showing IME screenshot. * @return {@code true} if successful, {@code false} otherwise. */ public abstract boolean removeImeScreenshot(int displayId); /** * Called from {@link DisplayContent#computeImeParent()} to check if we can compute the new IME * parent based on the given IME layering and IME input target. * * @param imeLayeringTarget The window the IME is on top of. * @param imeInputTarget The target which receives input from the IME. * @return {@code true} to keep computing the IME parent, {@code false} to defer this operation. */ public static boolean canComputeImeParent(@Nullable WindowState imeLayeringTarget, @Nullable InputTarget imeInputTarget) { if (imeLayeringTarget == null) { return false; } if (shouldComputeImeParentForEmbeddedActivity(imeLayeringTarget, imeInputTarget)) { return true; } // Ensure changing the IME parent when the layering target that may use IME has // became to the input target for preventing IME flickers. // Note that: // 1) For the imeLayeringTarget that may not use IME but requires IME on top // of it (e.g. an overlay window with NOT_FOCUSABLE|ALT_FOCUSABLE_IM flags), we allow // it to re-parent the IME on top the display to keep the legacy behavior. // 2) Even though the starting window won't use IME, the associated activity // behind the starting window may request the input. If so, then we should still hold // the IME parent change until the activity started the input. boolean imeLayeringTargetMayUseIme = WindowManager.LayoutParams.mayUseInputMethod(imeLayeringTarget.mAttrs.flags) || imeLayeringTarget.mAttrs.type == TYPE_APPLICATION_STARTING; // Do not change parent if the window hasn't requested IME. boolean inputAndLayeringTargetsDisagree = (imeInputTarget == null || imeLayeringTarget.mActivityRecord != imeInputTarget.getActivityRecord()); boolean inputTargetStale = imeLayeringTargetMayUseIme && inputAndLayeringTargetsDisagree; return !inputTargetStale; } /** * Called from {@link DisplayContent#computeImeParent()} to check if the IME surface parent * should be updated in ActivityEmbeddings, based on the given IME layering and IME input * target. * * <p>As the IME layering target is calculated according to the window hierarchy by * {@link DisplayContent#computeImeLayeringTarget}, the layering target and input target may be * different when the window hasn't started input connection, WindowManagerService hasn't yet * received the input target which reported from InputMethodManagerService. To make sure the IME * surface will be shown on the best fit IME layering target, we basically won't update IME * parent until both IME layering and input target are updated, for better IME transition. * * <p>However, in activity embedding, tapping a window won't update it to the top window so the * IME layering target may be higher than input target. Update IME parent in this case. * * @param imeLayeringTarget The window the IME is on top of. * @param imeInputTarget The target which receives input from the IME. * * @return {@code true} means the layer of IME layering target is higher than the input target * and {@link DisplayContent#computeImeParent()} should keep progressing to update the IME * surface parent on the display in case the IME surface was left behind. */ private static boolean shouldComputeImeParentForEmbeddedActivity( @Nullable WindowState imeLayeringTarget, @Nullable InputTarget imeInputTarget) { if (imeInputTarget == null || imeLayeringTarget == null) { return false; } final WindowState inputTargetWindow = imeInputTarget.getWindowState(); if (inputTargetWindow == null || !imeLayeringTarget.isAttached() || !inputTargetWindow.isAttached()) { return false; } final ActivityRecord inputTargetRecord = imeInputTarget.getActivityRecord(); final ActivityRecord layeringTargetRecord = imeLayeringTarget.getActivityRecord(); if (inputTargetRecord == null || layeringTargetRecord == null || inputTargetRecord == layeringTargetRecord || (inputTargetRecord.getTask() != layeringTargetRecord.getTask()) || !inputTargetRecord.isEmbedded() || !layeringTargetRecord.isEmbedded()) { // Check whether the input target and layering target are embedded in the same Task. return false; } return imeLayeringTarget.compareTo(inputTargetWindow) > 0; } } services/core/java/com/android/server/wm/WindowManagerInternal.java +17 −0 Original line number Diff line number Diff line Loading @@ -713,6 +713,23 @@ public abstract class WindowManagerInternal { */ public abstract void updateImeTargetWindow(@NonNull IBinder windowToken); /** * Shows the IME screenshot and attaches it to the given IME target window. * * @param imeTarget the token of the IME target window. * @param displayId the ID of the display to show the screenshot on. * @return {@code true} if successful, {@code false} otherwise. */ public abstract boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId); /** * Removes the IME screenshot from the given display. * * @param displayId The target display of showing IME screenshot. * @return {@code true} if successful, {@code false} otherwise. */ public abstract boolean removeImeScreenshot(int displayId); /** * Returns true when the hardware keyboard is available. */ Loading services/core/java/com/android/server/wm/WindowManagerService.java +32 −36 Original line number Diff line number Diff line Loading @@ -1514,8 +1514,6 @@ public class WindowManagerService extends IWindowManager.Stub mConstants.start(new HandlerExecutor(mH)); LocalServices.addService(WindowManagerInternal.class, new LocalService()); LocalServices.addService( ImeTargetVisibilityPolicy.class, new ImeTargetVisibilityPolicyImpl()); mEmbeddedWindowController = new EmbeddedWindowController(mAtmService, inputManager); mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources( Loading Loading @@ -8345,6 +8343,38 @@ public class WindowManagerService extends IWindowManager.Stub } } @Override public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId) { synchronized (mGlobalLock) { final WindowState imeTargetWindow = mWindowMap.get(imeTarget); if (imeTargetWindow == null) { return false; } final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to show IME screenshot"); return false; } dc.showImeScreenshot(imeTargetWindow); return true; } } @Override public boolean removeImeScreenshot(int displayId) { synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to remove IME screenshot"); return false; } dc.removeImeScreenshotImmediately(); return true; } } @Override public boolean isHardKeyboardAvailable() { synchronized (mGlobalLock) { Loading Loading @@ -9018,40 +9048,6 @@ public class WindowManagerService extends IWindowManager.Stub } } private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy { @Override public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId) { synchronized (mGlobalLock) { final WindowState imeTargetWindow = mWindowMap.get(imeTarget); if (imeTargetWindow == null) { return false; } final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to show IME screenshot"); return false; } dc.showImeScreenshot(imeTargetWindow); return true; } } @Override public boolean removeImeScreenshot(int displayId) { synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to remove IME screenshot"); return false; } dc.removeImeScreenshotImmediately(); return true; } } } /** Called to inform window manager if non-Vr UI shoul be disabled or not. */ public void disableNonVrUi(boolean disable) { synchronized (mGlobalLock) { Loading Loading
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +2 −6 Original line number Diff line number Diff line Loading @@ -192,7 +192,6 @@ import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeS import com.android.server.pm.UserManagerInternal; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.utils.PriorityDump; import com.android.server.wm.ImeTargetVisibilityPolicy; import com.android.server.wm.WindowManagerInternal; import java.io.FileDescriptor; Loading Loading @@ -409,8 +408,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. @MultiUserUnawareField private final InputMethodMenuController mMenuController; private final InputMethodMenuControllerNew mMenuControllerNew; @NonNull private final ImeTargetVisibilityPolicy mImeTargetVisibilityPolicy; /** * Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}. Loading Loading @@ -1217,7 +1214,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. mImePlatformCompatUtils = new ImePlatformCompatUtils(); mInputMethodDeviceConfigs = new InputMethodDeviceConfigs(); mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mImeTargetVisibilityPolicy = LocalServices.getService(ImeTargetVisibilityPolicy.class); mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime); Loading Loading @@ -5395,7 +5391,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. @VisibleForTesting @GuardedBy("ImfLock.class") void showImeScreenshot(IBinder imeTarget, int displayId, @UserIdInt int userId) { if (mImeTargetVisibilityPolicy.showImeScreenshot(imeTarget, displayId)) { if (mWindowManagerInternal.showImeScreenshot(imeTarget, displayId)) { onShowHideSoftInputRequested(false /* show */, imeTarget, SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS, null /* statsToken */, userId); Loading @@ -5412,7 +5408,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. @VisibleForTesting @GuardedBy("ImfLock.class") void removeImeScreenshot(IBinder imeTarget, int displayId, @UserIdInt int userId) { if (mImeTargetVisibilityPolicy.removeImeScreenshot(displayId)) { if (mWindowManagerInternal.removeImeScreenshot(displayId)) { onShowHideSoftInputRequested(false /* show */, imeTarget, SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS, null /* statsToken */, userId); Loading
services/core/java/com/android/server/wm/DisplayContent.java +81 −1 Original line number Diff line number Diff line Loading @@ -4902,7 +4902,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @VisibleForTesting @Nullable WindowContainer computeImeParent() { if (!ImeTargetVisibilityPolicy.canComputeImeParent(mImeLayeringTarget, mImeInputTarget)) { if (!canComputeImeParent(mImeLayeringTarget, mImeInputTarget)) { return null; } // Attach it to app if the IME layering target is part of an app that is covering the entire Loading @@ -4915,6 +4915,86 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return mImeWindowsContainer.getParent(); } /** * Called from {@link #computeImeParent()} to check if we can compute the new IME parent * based on the given IME layering and IME input target. * * @param imeLayeringTarget The window the IME is on top of. * @param imeInputTarget The target which receives input from the IME. * @return {@code true} to keep computing the IME parent, {@code false} to defer this operation. */ private static boolean canComputeImeParent(@Nullable WindowState imeLayeringTarget, @Nullable InputTarget imeInputTarget) { if (imeLayeringTarget == null) { return false; } if (shouldComputeImeParentForEmbeddedActivity(imeLayeringTarget, imeInputTarget)) { return true; } // Ensure changing the IME parent when the layering target that may use IME has // became to the input target for preventing IME flickers. // Note that: // 1) For the imeLayeringTarget that may not use IME but requires IME on top // of it (e.g. an overlay window with NOT_FOCUSABLE|ALT_FOCUSABLE_IM flags), we allow // it to re-parent the IME on top the display to keep the legacy behavior. // 2) Even though the starting window won't use IME, the associated activity // behind the starting window may request the input. If so, then we should still hold // the IME parent change until the activity started the input. boolean imeLayeringTargetMayUseIme = WindowManager.LayoutParams.mayUseInputMethod(imeLayeringTarget.mAttrs.flags) || imeLayeringTarget.mAttrs.type == TYPE_APPLICATION_STARTING; // Do not change parent if the window hasn't requested IME. boolean inputAndLayeringTargetsDisagree = (imeInputTarget == null || imeLayeringTarget.mActivityRecord != imeInputTarget.getActivityRecord()); boolean inputTargetStale = imeLayeringTargetMayUseIme && inputAndLayeringTargetsDisagree; return !inputTargetStale; } /** * Called from {@link #computeImeParent()} to check if the IME surface parent should be * updated in ActivityEmbeddings, based on the given IME layering and IME input target. * * <p>As the IME layering target is calculated according to the window hierarchy by * {@link #computeImeLayeringTarget}, the layering target and input target may be different * when the window hasn't started input connection, WindowManagerService hasn't yet received * the input target which reported from InputMethodManagerService. To make sure the IME * surface will be shown on the best fit IME layering target, we basically won't update IME * parent until both IME layering and input target are updated, for better IME transition. * * <p>However, in activity embedding, tapping a window won't update it to the top window so the * IME layering target may be higher than input target. Update IME parent in this case. * * @param imeLayeringTarget The window the IME is on top of. * @param imeInputTarget The target which receives input from the IME. * * @return {@code true} means the layer of IME layering target is higher than the input target * and {@link #computeImeParent()} should keep progressing to update the IME surface parent * on the display in case the IME surface was left behind. */ private static boolean shouldComputeImeParentForEmbeddedActivity( @Nullable WindowState imeLayeringTarget, @Nullable InputTarget imeInputTarget) { if (imeInputTarget == null || imeLayeringTarget == null) { return false; } final WindowState inputTargetWindow = imeInputTarget.getWindowState(); if (inputTargetWindow == null || !imeLayeringTarget.isAttached() || !inputTargetWindow.isAttached()) { return false; } final ActivityRecord inputTargetRecord = imeInputTarget.getActivityRecord(); final ActivityRecord layeringTargetRecord = imeLayeringTarget.getActivityRecord(); if (inputTargetRecord == null || layeringTargetRecord == null || inputTargetRecord == layeringTargetRecord || (inputTargetRecord.getTask() != layeringTargetRecord.getTask()) || !inputTargetRecord.isEmbedded() || !layeringTargetRecord.isEmbedded()) { // Check whether the input target and layering target are embedded in the same Task. return false; } return imeLayeringTarget.compareTo(inputTargetWindow) > 0; } void setLayoutNeeded() { if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3)); mLayoutNeeded = true; Loading
services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.javadeleted 100644 → 0 +0 −131 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IBinder; import android.view.WindowManager; /** * A class for {@link com.android.server.inputmethod.InputMethodManagerService} to * control IME visibility operations in {@link WindowManagerService}. */ public abstract class ImeTargetVisibilityPolicy { /** * Shows the IME screenshot and attaches it to the given IME target window. * * @param imeTarget the token of the IME target window. * @param displayId the ID of the display to show the screenshot on. * @return {@code true} if successful, {@code false} otherwise. */ public abstract boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId); /** * Removes the IME screenshot from the given display. * * @param displayId The target display of showing IME screenshot. * @return {@code true} if successful, {@code false} otherwise. */ public abstract boolean removeImeScreenshot(int displayId); /** * Called from {@link DisplayContent#computeImeParent()} to check if we can compute the new IME * parent based on the given IME layering and IME input target. * * @param imeLayeringTarget The window the IME is on top of. * @param imeInputTarget The target which receives input from the IME. * @return {@code true} to keep computing the IME parent, {@code false} to defer this operation. */ public static boolean canComputeImeParent(@Nullable WindowState imeLayeringTarget, @Nullable InputTarget imeInputTarget) { if (imeLayeringTarget == null) { return false; } if (shouldComputeImeParentForEmbeddedActivity(imeLayeringTarget, imeInputTarget)) { return true; } // Ensure changing the IME parent when the layering target that may use IME has // became to the input target for preventing IME flickers. // Note that: // 1) For the imeLayeringTarget that may not use IME but requires IME on top // of it (e.g. an overlay window with NOT_FOCUSABLE|ALT_FOCUSABLE_IM flags), we allow // it to re-parent the IME on top the display to keep the legacy behavior. // 2) Even though the starting window won't use IME, the associated activity // behind the starting window may request the input. If so, then we should still hold // the IME parent change until the activity started the input. boolean imeLayeringTargetMayUseIme = WindowManager.LayoutParams.mayUseInputMethod(imeLayeringTarget.mAttrs.flags) || imeLayeringTarget.mAttrs.type == TYPE_APPLICATION_STARTING; // Do not change parent if the window hasn't requested IME. boolean inputAndLayeringTargetsDisagree = (imeInputTarget == null || imeLayeringTarget.mActivityRecord != imeInputTarget.getActivityRecord()); boolean inputTargetStale = imeLayeringTargetMayUseIme && inputAndLayeringTargetsDisagree; return !inputTargetStale; } /** * Called from {@link DisplayContent#computeImeParent()} to check if the IME surface parent * should be updated in ActivityEmbeddings, based on the given IME layering and IME input * target. * * <p>As the IME layering target is calculated according to the window hierarchy by * {@link DisplayContent#computeImeLayeringTarget}, the layering target and input target may be * different when the window hasn't started input connection, WindowManagerService hasn't yet * received the input target which reported from InputMethodManagerService. To make sure the IME * surface will be shown on the best fit IME layering target, we basically won't update IME * parent until both IME layering and input target are updated, for better IME transition. * * <p>However, in activity embedding, tapping a window won't update it to the top window so the * IME layering target may be higher than input target. Update IME parent in this case. * * @param imeLayeringTarget The window the IME is on top of. * @param imeInputTarget The target which receives input from the IME. * * @return {@code true} means the layer of IME layering target is higher than the input target * and {@link DisplayContent#computeImeParent()} should keep progressing to update the IME * surface parent on the display in case the IME surface was left behind. */ private static boolean shouldComputeImeParentForEmbeddedActivity( @Nullable WindowState imeLayeringTarget, @Nullable InputTarget imeInputTarget) { if (imeInputTarget == null || imeLayeringTarget == null) { return false; } final WindowState inputTargetWindow = imeInputTarget.getWindowState(); if (inputTargetWindow == null || !imeLayeringTarget.isAttached() || !inputTargetWindow.isAttached()) { return false; } final ActivityRecord inputTargetRecord = imeInputTarget.getActivityRecord(); final ActivityRecord layeringTargetRecord = imeLayeringTarget.getActivityRecord(); if (inputTargetRecord == null || layeringTargetRecord == null || inputTargetRecord == layeringTargetRecord || (inputTargetRecord.getTask() != layeringTargetRecord.getTask()) || !inputTargetRecord.isEmbedded() || !layeringTargetRecord.isEmbedded()) { // Check whether the input target and layering target are embedded in the same Task. return false; } return imeLayeringTarget.compareTo(inputTargetWindow) > 0; } }
services/core/java/com/android/server/wm/WindowManagerInternal.java +17 −0 Original line number Diff line number Diff line Loading @@ -713,6 +713,23 @@ public abstract class WindowManagerInternal { */ public abstract void updateImeTargetWindow(@NonNull IBinder windowToken); /** * Shows the IME screenshot and attaches it to the given IME target window. * * @param imeTarget the token of the IME target window. * @param displayId the ID of the display to show the screenshot on. * @return {@code true} if successful, {@code false} otherwise. */ public abstract boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId); /** * Removes the IME screenshot from the given display. * * @param displayId The target display of showing IME screenshot. * @return {@code true} if successful, {@code false} otherwise. */ public abstract boolean removeImeScreenshot(int displayId); /** * Returns true when the hardware keyboard is available. */ Loading
services/core/java/com/android/server/wm/WindowManagerService.java +32 −36 Original line number Diff line number Diff line Loading @@ -1514,8 +1514,6 @@ public class WindowManagerService extends IWindowManager.Stub mConstants.start(new HandlerExecutor(mH)); LocalServices.addService(WindowManagerInternal.class, new LocalService()); LocalServices.addService( ImeTargetVisibilityPolicy.class, new ImeTargetVisibilityPolicyImpl()); mEmbeddedWindowController = new EmbeddedWindowController(mAtmService, inputManager); mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources( Loading Loading @@ -8345,6 +8343,38 @@ public class WindowManagerService extends IWindowManager.Stub } } @Override public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId) { synchronized (mGlobalLock) { final WindowState imeTargetWindow = mWindowMap.get(imeTarget); if (imeTargetWindow == null) { return false; } final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to show IME screenshot"); return false; } dc.showImeScreenshot(imeTargetWindow); return true; } } @Override public boolean removeImeScreenshot(int displayId) { synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to remove IME screenshot"); return false; } dc.removeImeScreenshotImmediately(); return true; } } @Override public boolean isHardKeyboardAvailable() { synchronized (mGlobalLock) { Loading Loading @@ -9018,40 +9048,6 @@ public class WindowManagerService extends IWindowManager.Stub } } private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy { @Override public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId) { synchronized (mGlobalLock) { final WindowState imeTargetWindow = mWindowMap.get(imeTarget); if (imeTargetWindow == null) { return false; } final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to show IME screenshot"); return false; } dc.showImeScreenshot(imeTargetWindow); return true; } } @Override public boolean removeImeScreenshot(int displayId) { synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to remove IME screenshot"); return false; } dc.removeImeScreenshotImmediately(); return true; } } } /** Called to inform window manager if non-Vr UI shoul be disabled or not. */ public void disableNonVrUi(boolean disable) { synchronized (mGlobalLock) { Loading