diff options
| author | 2022-12-09 06:49:46 +0000 | |
|---|---|---|
| committer | 2023-01-11 02:09:29 +0000 | |
| commit | a549d5a462f5aba3f0846490d3df61c62cf8c37a (patch) | |
| tree | 7396963fddd282cf87b5f4f8306e5d7e53e446e6 | |
| parent | cc573687c72b3fe6cf61af639304422e78050d58 (diff) | |
Remove IMMS#mShowRequested
Now we have ImeTargetWindow#isRequestedImeVisible as per-window state,
To avoid this global visible state may cause some system controlled IME
visiblity issues, replace mShowRequested with
IMMS#isShowRequestedForCurrentWindow() to get the requested IME visible
state from the current focused window.
Also, in case in IMMS side may not be able to restore the IME visibility
when the activity got relaunched, updates AR#mLastImeShown state when
relaunching the activity without preserving window, and modifies
shouldRestoreImeVisiblity(windowToken) for IMMS to restore the last IME
visiblity state for that relaunching activity window.
Bug: 246309664
Test: atest InputMethodVisibilityControlTest
Test: atest CtsInputMethodDeviceTests
Change-Id: I9e69043d4aeaa2931ea192692007c7ca6420a107
6 files changed, 68 insertions, 31 deletions
diff --git a/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto b/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto index 35aae8f92d93..5a18d9e627e8 100644 --- a/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto +++ b/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto @@ -31,7 +31,7 @@ message InputMethodManagerServiceProto { optional string cur_focused_window_soft_input_mode = 6; optional .android.view.inputmethod.EditorInfoProto cur_attribute = 7; optional string cur_id = 8; - optional bool show_requested = 9; + reserved 9; // deprecated show_requested optional bool show_explicitly_requested = 10; optional bool show_forced = 11; optional bool input_shown = 12; diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java index 9bc91b849cc9..795e4bf9d5cb 100644 --- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java +++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java @@ -254,9 +254,16 @@ public final class ImeVisibilityStateComputer { * {@link #STATE_HIDE_IME}. */ void requestImeVisibility(IBinder windowToken, boolean showIme) { - final ImeTargetWindowState state = getOrCreateWindowState(windowToken); - state.setRequestedImeVisible(showIme); - setWindowState(windowToken, state); + ImeTargetWindowState state = getOrCreateWindowState(windowToken); + if (!mPolicy.mPendingA11yRequestingHideKeyboard) { + state.setRequestedImeVisible(showIme); + } else { + // As A11y requests no IME is just a temporary, so we don't change the requested IME + // visible in case the last visibility state goes wrong after leaving from the a11y + // policy. + mPolicy.mPendingA11yRequestingHideKeyboard = false; + } + setWindowStateInner(windowToken, state); } ImeTargetWindowState getOrCreateWindowState(IBinder windowToken) { @@ -276,12 +283,22 @@ public final class ImeVisibilityStateComputer { ImeTargetWindowState state = getWindowStateOrNull(windowToken); if (state != null) { state.setRequestImeToken(token); - setWindowState(windowToken, state); + setWindowStateInner(windowToken, state); + } + } + + void setWindowState(IBinder windowToken, @NonNull ImeTargetWindowState newState) { + final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken); + if (state != null && newState.hasEdiorFocused()) { + // Inherit the last requested IME visible state when the target window is still + // focused with an editor. + newState.setRequestedImeVisible(state.mRequestedImeVisible); } + setWindowStateInner(windowToken, newState); } - void setWindowState(IBinder windowToken, ImeTargetWindowState newState) { - if (DEBUG) Slog.d(TAG, "setWindowState, windowToken=" + windowToken + private void setWindowStateInner(IBinder windowToken, @NonNull ImeTargetWindowState newState) { + if (DEBUG) Slog.d(TAG, "setWindowStateInner, windowToken=" + windowToken + ", state=" + newState); mRequestWindowStateMap.put(windowToken, newState); } @@ -330,6 +347,10 @@ public final class ImeVisibilityStateComputer { // UI for input. if (state.hasEdiorFocused() && shouldRestoreImeVisibility(state)) { if (DEBUG) Slog.v(TAG, "Will show input to restore visibility"); + // Inherit the last requested IME visible state when the target window is still + // focused with an editor. + state.setRequestedImeVisible(true); + setWindowStateInner(getWindowTokenFrom(state), state); return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT, SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY); } @@ -512,6 +533,14 @@ public final class ImeVisibilityStateComputer { */ private boolean mA11yRequestingNoSoftKeyboard; + /** + * Used when A11y request to hide IME temporary when receiving + * {@link AccessibilityService#SHOW_MODE_HIDDEN} from + * {@link android.provider.Settings.Secure#ACCESSIBILITY_SOFT_KEYBOARD_MODE} without + * changing the requested IME visible state. + */ + private boolean mPendingA11yRequestingHideKeyboard; + void setImeHiddenByDisplayPolicy(boolean hideIme) { mImeHiddenByDisplayPolicy = hideIme; } @@ -523,6 +552,9 @@ public final class ImeVisibilityStateComputer { void setA11yRequestNoSoftKeyboard(int keyboardShowMode) { mA11yRequestingNoSoftKeyboard = (keyboardShowMode & AccessibilityService.SHOW_MODE_MASK) == SHOW_MODE_HIDDEN; + if (mA11yRequestingNoSoftKeyboard) { + mPendingA11yRequestingHideKeyboard = true; + } } boolean isA11yRequestNoSoftKeyboard() { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 079234c2f95c..187de930cff3 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -350,7 +350,7 @@ final class InputMethodBindingController { // should now try to restart the service for us. mLastBindTime = SystemClock.uptimeMillis(); clearCurMethodAndSessions(); - mService.clearInputShowRequestLocked(); + mService.clearInputShownLocked(); mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME); } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 076673651490..a94c90c8ee63 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -38,7 +38,6 @@ import static android.server.inputmethod.InputMethodManagerServiceProto.IS_INTER import static android.server.inputmethod.InputMethodManagerServiceProto.LAST_IME_TARGET_WINDOW_NAME; import static android.server.inputmethod.InputMethodManagerServiceProto.LAST_SWITCH_USER_ID; import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_IME_WITH_HARD_KEYBOARD; -import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_REQUESTED; import static android.server.inputmethod.InputMethodManagerServiceProto.SYSTEM_READY; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; @@ -623,11 +622,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return mBindingController.hasConnection(); } - /** - * Set if the client has asked for the input method to be shown. - */ - private boolean mShowRequested; - /** The token tracking the current IME request or {@code null} otherwise. */ @Nullable private ImeTracker.Token mCurStatsToken; @@ -1168,12 +1162,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub mVisibilityStateComputer.getImePolicy().setA11yRequestNoSoftKeyboard( accessibilitySoftKeyboardSetting); if (mVisibilityStateComputer.getImePolicy().isA11yRequestNoSoftKeyboard()) { - final boolean showRequested = mShowRequested; hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */, null /* resultReceiver */, SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE); - mShowRequested = showRequested; - } else if (mShowRequested) { + } else if (isShowRequestedForCurrentWindow()) { showCurrentInputImplicitLocked(mCurFocusedWindow, SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE); } @@ -2293,8 +2285,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("ImfLock.class") - void clearInputShowRequestLocked() { - mShowRequested = mVisibilityStateComputer.isInputShown(); + void clearInputShownLocked() { mVisibilityStateComputer.setInputShown(false); } @@ -2304,6 +2295,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("ImfLock.class") + private boolean isShowRequestedForCurrentWindow() { + final ImeTargetWindowState state = mVisibilityStateComputer.getWindowStateOrNull( + mCurFocusedWindow); + return state != null && state.isRequestedImeVisible(); + } + + @GuardedBy("ImfLock.class") @NonNull InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) { if (!mBoundToMethod) { @@ -2339,7 +2337,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub setEnabledSessionLocked(session); session.mMethod.startInput(startInputToken, mCurInputConnection, mCurEditorInfo, restarting, navButtonFlags, mCurImeDispatcher); - if (mShowRequested) { + if (isShowRequestedForCurrentWindow()) { if (DEBUG) Slog.v(TAG, "Attach new input asks to show input"); // Re-use current statsToken, if it exists. final ImeTracker.Token statsToken = mCurStatsToken; @@ -2558,7 +2556,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (!mPreventImeStartupUnlessTextEditor) { return false; } - if (mShowRequested) { + if (isShowRequestedForCurrentWindow()) { return false; } if (isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, startInputFlags)) { @@ -3369,9 +3367,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub ImeTracker.ORIGIN_SERVER_START_INPUT, reason); } - // TODO(b/246309664): make mShowRequested as per-window state. - mShowRequested = true; - if (!mVisibilityStateComputer.onImeShowFlags(statsToken, flags)) { return false; } @@ -3466,7 +3461,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub // application process as a valid request, and have even promised such a behavior with CTS // since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only // IMMS#InputShown indicates that the software keyboard is shown. - // TODO(b/246309664): Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested. + // TODO(b/246309664): Clean up IMMS#mImeWindowVis IInputMethodInvoker curMethod = getCurMethodLocked(); final boolean shouldHideSoftInput = curMethod != null && (isInputShown() || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0); @@ -3484,7 +3479,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } mBindingController.setCurrentMethodNotVisible(); mVisibilityStateComputer.clearImeShowFlags(); - mShowRequested = false; // Cancel existing statsToken for show IME as we got a hide request. ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME); mCurStatsToken = null; @@ -3699,7 +3693,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.computeState(windowState, isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, startInputFlags)); if (imeVisRes != null) { - switch(imeVisRes.getReason()) { + switch (imeVisRes.getReason()) { case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY: case SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV: case SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV: @@ -4502,7 +4496,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub mCurEditorInfo.dumpDebug(proto, CUR_ATTRIBUTE); } proto.write(CUR_ID, getCurIdLocked()); - proto.write(SHOW_REQUESTED, mShowRequested); mVisibilityStateComputer.dumpDebug(proto, fieldId); proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode); proto.write(CUR_TOKEN, Objects.toString(getCurTokenLocked())); @@ -4750,7 +4743,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub synchronized (ImfLock.class) { try { if (mEnabledSession != null && mEnabledSession.mSession != null - && !mShowRequested) { + && !isShowRequestedForCurrentWindow()) { mEnabledSession.mSession.removeImeSurface(); } } catch (RemoteException e) { @@ -5738,7 +5731,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub method = getCurMethodLocked(); p.println(" mCurMethod=" + getCurMethodLocked()); p.println(" mEnabledSession=" + mEnabledSession); - p.println(" mShowRequested=" + mShowRequested); mVisibilityStateComputer.dump(pw); p.println(" mInFullscreenMode=" + mInFullscreenMode); p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 841094221d99..66f6a3fb5cc0 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -9360,6 +9360,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A configChangeFlags = 0; return; } + if (!preserveWindow) { + // If the activity is the IME input target, ensure storing the last IME shown state + // before relaunching it for restoring the IME visibility once its new window focused. + final InputTarget imeInputTarget = mDisplayContent.getImeInputTarget(); + mLastImeShown = imeInputTarget != null && imeInputTarget.getWindowState() != null + && imeInputTarget.getWindowState().mActivityRecord == this + && mDisplayContent.mInputMethodWindow != null + && mDisplayContent.mInputMethodWindow.isVisible(); + } // Do not waiting for translucent activity if it is going to relaunch. final Task rootTask = getRootTask(); if (rootTask != null && rootTask.mTranslucentActivityWaiting == this) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 79830477ea3d..9b845cd8285e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -9139,6 +9139,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) { final Task imeTargetWindowTask; + boolean hadRequestedShowIme = false; synchronized (mGlobalLock) { final WindowState imeTargetWindow = mWindowMap.get(imeTargetWindowToken); if (imeTargetWindow == null) { @@ -9148,11 +9149,14 @@ public class WindowManagerService extends IWindowManager.Stub if (imeTargetWindowTask == null) { return false; } + if (imeTargetWindow.mActivityRecord != null) { + hadRequestedShowIme = imeTargetWindow.mActivityRecord.mLastImeShown; + } } final TaskSnapshot snapshot = getTaskSnapshot(imeTargetWindowTask.mTaskId, imeTargetWindowTask.mUserId, false /* isLowResolution */, false /* restoreFromDisk */); - return snapshot != null && snapshot.hasImeSurface(); + return snapshot != null && snapshot.hasImeSurface() || hadRequestedShowIme; } @Override |