diff options
| author | 2023-05-05 09:34:05 +0000 | |
|---|---|---|
| committer | 2023-05-08 17:52:38 +0000 | |
| commit | 8fb9afd6559357f6583f19b04422312749ca910e (patch) | |
| tree | 12c1f0085f6b32dc0932430d8b0126d4c37cae26 | |
| parent | 957410032e8f8e226cfdba8cf4abfcb415a0e7bc (diff) | |
Fix ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest flaky
As CL[1] that ImeVisibilityStateComputer leverages
onImeInputTargetVisibilityChanged callback to check whether the current
IME input target has been covered and became invisible by non-IME focusable
layering target. If so then ImeVisibilityStateComputer will hide the IME
to address the IME persists on top of layering target but the input target
was invisible case.
But there is an edge case that the starting window could possible shown
and cover the IME input target befor it drawn during animating (e.g.
quick-switching app tasks by recents animation) then leads to IME may
hidden by CL[1]'s case.
Luckly the above scenario has caught by
ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest, to fix this
flaky case, add the windowType in onImeTargetOverlayVisibilityChanged
to give more context for ImeVisibilityStateComputer and ignore the starting
window case, since it since it's ok to cover the IME input target window
in temporary without affecting the IME visibility.
[1]: Ia71b975898efb19439c3a1b1a9a2bdcf21b78650
Fix: 278698977
Test: atest
FlickerTest:ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest
--rerun-until-failure 10
Test: atest ImeVisibilityStateComputerTest
Change-Id: I3a950423f73f0a97432589d0a90ac8fd1c84f05e
6 files changed, 31 insertions, 12 deletions
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java index 19d6fa00a270..f012d917b05e 100644 --- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java +++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java @@ -27,6 +27,7 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVI import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED; import static android.view.WindowManager.LayoutParams.SoftInputModeFlags; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static com.android.internal.inputmethod.InputMethodDebug.softInputModeToString; import static com.android.internal.inputmethod.SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS; @@ -195,19 +196,25 @@ public final class ImeVisibilityStateComputer { mWindowManagerInternal.setInputMethodTargetChangeListener(new ImeTargetChangeListener() { @Override public void onImeTargetOverlayVisibilityChanged(IBinder overlayWindowToken, - boolean visible, boolean removed) { - mCurVisibleImeLayeringOverlay = (visible && !removed) ? overlayWindowToken : null; + @WindowManager.LayoutParams.WindowType int windowType, boolean visible, + boolean removed) { + mCurVisibleImeLayeringOverlay = + // Ignoring the starting window since it's ok to cover the IME target + // window in temporary without affecting the IME visibility. + (visible && !removed && windowType != TYPE_APPLICATION_STARTING) + ? overlayWindowToken : null; } @Override public void onImeInputTargetVisibilityChanged(IBinder imeInputTarget, boolean visibleRequested, boolean removed) { - mCurVisibleImeInputTarget = (visibleRequested && !removed) ? imeInputTarget : null; - if (mCurVisibleImeInputTarget == null && mCurVisibleImeLayeringOverlay != null) { + if (mCurVisibleImeInputTarget == imeInputTarget && (!visibleRequested || removed) + && mCurVisibleImeLayeringOverlay != null) { mService.onApplyImeVisibilityFromComputer(imeInputTarget, new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT, SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE)); } + mCurVisibleImeInputTarget = (visibleRequested && !removed) ? imeInputTarget : null; } }); } diff --git a/services/core/java/com/android/server/wm/ImeTargetChangeListener.java b/services/core/java/com/android/server/wm/ImeTargetChangeListener.java index 8bc445bc97bb..88b76aaa6992 100644 --- a/services/core/java/com/android/server/wm/ImeTargetChangeListener.java +++ b/services/core/java/com/android/server/wm/ImeTargetChangeListener.java @@ -18,6 +18,7 @@ package com.android.server.wm; import android.annotation.NonNull; import android.os.IBinder; +import android.view.WindowManager; /** * Callback the IME targeting window visibility change state for @@ -32,11 +33,13 @@ public interface ImeTargetChangeListener { * has changed its window visibility. * * @param overlayWindowToken the window token of the overlay window. + * @param windowType the window type of the overlay window. * @param visible the visibility of the overlay window, {@code true} means visible * and {@code false} otherwise. * @param removed Whether the IME target overlay window has being removed. */ default void onImeTargetOverlayVisibilityChanged(@NonNull IBinder overlayWindowToken, + @WindowManager.LayoutParams.WindowType int windowType, boolean visible, boolean removed) { } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8baf048980ed..546be2c0b46c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -283,6 +283,7 @@ import android.view.SurfaceControlViewHost; import android.view.SurfaceSession; import android.view.TaskTransitionSpec; import android.view.View; +import android.view.ViewDebug; import android.view.WindowContentFrameStats; import android.view.WindowInsets; import android.view.WindowInsets.Type.InsetsType; @@ -1811,7 +1812,7 @@ public class WindowManagerService extends IWindowManager.Stub if (imMayMove) { displayContent.computeImeTarget(true /* updateImeTarget */); if (win.isImeOverlayLayeringTarget()) { - dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), + dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), win.mAttrs.type, win.isVisibleRequestedOrAdding(), false /* removed */); } } @@ -2521,7 +2522,7 @@ public class WindowManagerService extends IWindowManager.Stub final boolean winVisibleChanged = win.isVisible() != wasVisible; if (win.isImeOverlayLayeringTarget() && winVisibleChanged) { - dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), + dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), win.mAttrs.type, win.isVisible(), false /* removed */); } // Notify listeners about IME input target window visibility change. @@ -3355,15 +3356,17 @@ public class WindowManagerService extends IWindowManager.Stub }); } - void dispatchImeTargetOverlayVisibilityChanged(@NonNull IBinder token, boolean visible, + void dispatchImeTargetOverlayVisibilityChanged(@NonNull IBinder token, + @WindowManager.LayoutParams.WindowType int windowType, boolean visible, boolean removed) { if (mImeTargetChangeListener != null) { if (DEBUG_INPUT_METHOD) { Slog.d(TAG, "onImeTargetOverlayVisibilityChanged, win=" + mWindowMap.get(token) - + "visible=" + visible + ", removed=" + removed); + + ", type=" + ViewDebug.intToString(WindowManager.LayoutParams.class, + "type", windowType) + "visible=" + visible + ", removed=" + removed); } mH.post(() -> mImeTargetChangeListener.onImeTargetOverlayVisibilityChanged(token, - visible, removed)); + windowType, visible, removed)); } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 032f08a92abb..b69262e4b154 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2349,7 +2349,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP super.removeImmediately(); if (isImeOverlayLayeringTarget()) { - mWmService.dispatchImeTargetOverlayVisibilityChanged(mClient.asBinder(), + mWmService.dispatchImeTargetOverlayVisibilityChanged(mClient.asBinder(), mAttrs.type, false /* visible */, true /* removed */); } final DisplayContent dc = getDisplayContent(); diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java index 3871e1dfd5b0..a38c1626aea1 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java @@ -23,6 +23,7 @@ import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE; import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE; @@ -241,8 +242,12 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes final IBinder testImeTargetOverlay = new Binder(); final IBinder testImeInputTarget = new Binder(); + // Simulate a test IME input target was visible. + mListener.onImeInputTargetVisibilityChanged(testImeInputTarget, true, false); + // Simulate a test IME layering target overlay fully occluded the IME input target. - mListener.onImeTargetOverlayVisibilityChanged(testImeTargetOverlay, true, false); + mListener.onImeTargetOverlayVisibilityChanged(testImeTargetOverlay, + TYPE_APPLICATION_OVERLAY, true, false); mListener.onImeInputTargetVisibilityChanged(testImeInputTarget, false, false); final ArgumentCaptor<IBinder> targetCaptor = ArgumentCaptor.forClass(IBinder.class); final ArgumentCaptor<ImeVisibilityResult> resultCaptor = ArgumentCaptor.forClass( diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index ee1afcf318fa..0ddd3135506e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -1390,7 +1390,8 @@ public class WindowStateTests extends WindowTestsBase { private boolean mIsVisibleForImeInputTarget; @Override - public void onImeTargetOverlayVisibilityChanged(IBinder overlayWindowToken, boolean visible, + public void onImeTargetOverlayVisibilityChanged(IBinder overlayWindowToken, + @WindowManager.LayoutParams.WindowType int windowType, boolean visible, boolean removed) { mImeTargetToken = overlayWindowToken; mIsVisibleForImeTargetOverlay = visible; |