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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user