From e99a1b491d170ffe000315a37ebc577106a1bd8a Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Wed, 4 Nov 2020 02:06:01 +0800 Subject: [PATCH] Restore the last IME visiblity of the app window when allowed Since when bring an existing app task to foreground or quick switching app task with gesture navigation will first see the task snapshot during app transition, If the task previously focused and shown IME, even the task may hide IME when switching to the next task, As the goal of go/ime-transition-improve-s mentioned, if the task is still focused by editor, we should keep the original focused IME shown and keep the input connection focused state when navigating back to the original task. Bug: 166736352 Test: atest CtsInputMethodTestcases Test: manual by focusing app with an editor to show keyboard, switch the app task to the next with gesture nav and then switched back, expected the soft-keyboard is still shown. Change-Id: I63b144bed6c37569d79fba1c2b63dd4f1074f0f6 --- .../java/android/view/ImeFocusController.java | 5 +++-- .../inputmethod/InputMethodDebug.java | 2 ++ .../inputmethod/SoftInputShowHideReason.java | 9 +++++++- .../InputMethodManagerService.java | 14 +++++++++++++ .../server/wm/WindowManagerInternal.java | 9 ++++++++ .../server/wm/WindowManagerService.java | 21 +++++++++++++++++++ 6 files changed, 57 insertions(+), 3 deletions(-) diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java index 4a5c95f43d462..d23a1e5992cce 100644 --- a/core/java/android/view/ImeFocusController.java +++ b/core/java/android/view/ImeFocusController.java @@ -116,8 +116,9 @@ public final class ImeFocusController { if (!hasWindowFocus || !mHasImeFocus || isInLocalFocusMode(windowAttribute)) { return; } + View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView; if (DEBUG) { - Log.v(TAG, "onWindowFocus: " + focusedView + Log.v(TAG, "onWindowFocus: " + viewForWindowFocus + " softInputMode=" + InputMethodDebug.softInputModeToString( windowAttribute.softInputMode)); } @@ -128,8 +129,8 @@ public final class ImeFocusController { if (DEBUG) Log.v(TAG, "Restarting due to isRestartOnNextWindowFocus as true"); forceFocus = true; } + // Update mNextServedView when focusedView changed. - final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView; onViewFocusChanged(viewForWindowFocus, true); // Starting new input when the next focused view is same as served view but the currently diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java index c353de88dc3b3..93374ba0cf464 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java +++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java @@ -228,6 +228,8 @@ public final class InputMethodDebug { return "HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR"; case SoftInputShowHideReason.HIDE_REMOVE_CLIENT: return "HIDE_REMOVE_CLIENT"; + case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY: + return "SHOW_RESTORE_IME_VISIBILITY"; default: return "Unknown=" + reason; } diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java index 1553e2eb07939..f1cdf2b38c4c5 100644 --- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java +++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java @@ -49,7 +49,8 @@ import java.lang.annotation.Retention; SoftInputShowHideReason.HIDE_RECENTS_ANIMATION, SoftInputShowHideReason.HIDE_BUBBLES, SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR, - SoftInputShowHideReason.HIDE_REMOVE_CLIENT}) + SoftInputShowHideReason.HIDE_REMOVE_CLIENT, + SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY}) public @interface SoftInputShowHideReason { /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */ int SHOW_SOFT_INPUT = 0; @@ -167,4 +168,10 @@ public @interface SoftInputShowHideReason { * Hide soft input when a {@link com.android.internal.view.IInputMethodClient} is removed. */ int HIDE_REMOVE_CLIENT = 21; + + /** + * Show soft input when the system invoking + * {@link com.android.server.wm.WindowManagerInternal#shouldRestoreImeVisibility}. + */ + int SHOW_RESTORE_IME_VISIBILITY = 22; } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 1e66589308404..ae576fa9996e4 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -3537,6 +3537,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub boolean didStart = false; InputBindResult res = null; + // We shows the IME when the system allows the IME focused target window to restore the + // IME visibility (e.g. switching to the app task when last time the IME is visible). + if (isTextEditor && mWindowManagerInternal.shouldRestoreImeVisibility(windowToken)) { + if (attribute != null) { + res = startInputUncheckedLocked(cs, inputContext, missingMethods, + attribute, startInputFlags, startInputReason); + showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null, + SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY); + } else { + res = InputBindResult.NULL_EDITOR_INFO; + } + return res; + } + switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) { case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED: if (!sameWindowFocused && (!isTextEditor || !doAutoShow)) { diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index e183ea0d81abb..e03198d63b4cc 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -667,4 +667,13 @@ public abstract class WindowManagerInternal { * Moves the {@link WindowToken} {@code binder} to the display specified by {@code displayId}. */ public abstract void moveWindowTokenToDisplay(IBinder binder, int displayId); + + /** + * Checks whether the given window should restore the last IME visibility. + * + * @param imeTargetWindowToken The token of the (IME target) window + * @return {@code true} when the system allows to restore the IME visibility, + * {@code false} otherwise. + */ + public abstract boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 89d30408fe25c..aad9574911b67 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -8016,6 +8016,11 @@ public class WindowManagerService extends IWindowManager.Stub return dc.getImeTarget(IME_TARGET_LAYERING).getWindow().getName(); } } + + @Override + public boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) { + return WindowManagerService.this.shouldRestoreImeVisibility(imeTargetWindowToken); + } } void registerAppFreezeListener(AppFreezeListener listener) { @@ -8673,6 +8678,22 @@ public class WindowManagerService extends IWindowManager.Stub boundsInWindow, hashAlgorithm, callback); } + boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) { + synchronized (mGlobalLock) { + final WindowState imeTargetWindow = mWindowMap.get(imeTargetWindowToken); + if (imeTargetWindow == null) { + return false; + } + final Task imeTargetWindowTask = imeTargetWindow.getTask(); + if (imeTargetWindowTask == null) { + return false; + } + final TaskSnapshot snapshot = mAtmService.getTaskSnapshot(imeTargetWindowTask.mTaskId, + false /* isLowResolution */); + return snapshot != null && snapshot.hasImeSurface(); + } + } + private void sendDisplayHashError(RemoteCallback callback, int errorCode) { Bundle bundle = new Bundle(); bundle.putInt(EXTRA_DISPLAY_HASH_ERROR_CODE, errorCode);