summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ming-Shin Lu <lumark@google.com> 2023-05-05 09:34:05 +0000
committer Ming-Shin Lu <lumark@google.com> 2023-05-08 17:52:38 +0000
commit8fb9afd6559357f6583f19b04422312749ca910e (patch)
tree12c1f0085f6b32dc0932430d8b0126d4c37cae26
parent957410032e8f8e226cfdba8cf4abfcb415a0e7bc (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
-rw-r--r--services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java15
-rw-r--r--services/core/java/com/android/server/wm/ImeTargetChangeListener.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java2
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java3
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;