Merge "Don't dispatch IME insets if the target is above IME" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
0e503e5ebb
@@ -659,6 +659,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
// When non-null, new tasks get put into this root task.
|
||||
Task mLaunchRootTask = null;
|
||||
|
||||
// Used in performing layout
|
||||
private boolean mTmpWindowsBehindIme;
|
||||
|
||||
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
|
||||
WindowStateAnimator winAnimator = w.mWinAnimator;
|
||||
final ActivityRecord activity = w.mActivityRecord;
|
||||
@@ -750,6 +753,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
+ " parentHidden=" + w.isParentWindowHidden());
|
||||
}
|
||||
|
||||
// Sets mBehindIme for each window. Windows behind IME can get IME insets.
|
||||
w.mBehindIme = mTmpWindowsBehindIme;
|
||||
if (w == mInputMethodWindow) {
|
||||
mTmpWindowsBehindIme = true;
|
||||
}
|
||||
|
||||
// If this view is GONE, then skip it -- keep the current frame, and let the caller know
|
||||
// so they can ignore it if they want. (We do the normal layout for INVISIBLE windows,
|
||||
// since that means "perform layout as normal, just don't display").
|
||||
@@ -4016,6 +4025,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
mTmpWindow = null;
|
||||
mTmpInitial = initial;
|
||||
|
||||
// Used to indicate that we have processed the IME window.
|
||||
mTmpWindowsBehindIme = false;
|
||||
|
||||
// First perform layout of any root windows (not attached to another window).
|
||||
forAllWindows(mPerformLayout, true /* traverseTopToBottom */);
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
|
||||
import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
|
||||
import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
|
||||
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
|
||||
import static android.view.InsetsState.ITYPE_IME;
|
||||
import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
|
||||
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
|
||||
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
||||
@@ -1493,14 +1492,8 @@ public class DisplayPolicy {
|
||||
*/
|
||||
public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
|
||||
displayFrames.onBeginLayout();
|
||||
final InsetsState insetsState =
|
||||
mDisplayContent.getInsetsStateController().getRawInsetsState();
|
||||
|
||||
// Reset the frame of IME so that the layout of windows above IME won't get influenced.
|
||||
// Once we layout the IME, frames will be set again on the source.
|
||||
insetsState.getSource(ITYPE_IME).setFrame(0, 0, 0, 0);
|
||||
|
||||
updateInsetsStateForDisplayCutout(displayFrames, insetsState);
|
||||
updateInsetsStateForDisplayCutout(displayFrames,
|
||||
mDisplayContent.getInsetsStateController().getRawInsetsState());
|
||||
mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
|
||||
mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
|
||||
|
||||
|
||||
@@ -88,8 +88,8 @@ class InsetsStateController {
|
||||
final InsetsSourceProvider provider = target.getControllableInsetProvider();
|
||||
final @InternalInsetsType int type = provider != null
|
||||
? provider.getSource().getType() : ITYPE_INVALID;
|
||||
return getInsetsForTypeAndWindowingMode(type, target.getWindowingMode(),
|
||||
target.isAlwaysOnTop());
|
||||
return getInsetsForDispatchInner(type, target.getWindowingMode(), target.isAlwaysOnTop(),
|
||||
isAboveIme(target));
|
||||
}
|
||||
|
||||
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
|
||||
@@ -97,13 +97,24 @@ class InsetsStateController {
|
||||
final WindowToken token = mDisplayContent.getWindowToken(attrs.token);
|
||||
final @WindowingMode int windowingMode = token != null
|
||||
? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
|
||||
final boolean alwaysOnTop = token != null
|
||||
? token.isAlwaysOnTop() : false;
|
||||
return getInsetsForTypeAndWindowingMode(type, windowingMode, alwaysOnTop);
|
||||
final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
|
||||
return getInsetsForDispatchInner(type, windowingMode, alwaysOnTop, isAboveIme(token));
|
||||
}
|
||||
|
||||
private boolean isAboveIme(WindowContainer target) {
|
||||
final WindowState imeWindow = mDisplayContent.mInputMethodWindow;
|
||||
if (target == null || imeWindow == null) {
|
||||
return false;
|
||||
}
|
||||
if (target instanceof WindowState) {
|
||||
final WindowState win = (WindowState) target;
|
||||
return win.needsRelativeLayeringToIme() || !win.mBehindIme;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static @InternalInsetsType int getInsetsTypeForWindowType(int type) {
|
||||
switch(type) {
|
||||
switch (type) {
|
||||
case TYPE_STATUS_BAR:
|
||||
return ITYPE_STATUS_BAR;
|
||||
case TYPE_NAVIGATION_BAR:
|
||||
@@ -116,8 +127,8 @@ class InsetsStateController {
|
||||
}
|
||||
|
||||
/** @see #getInsetsForDispatch */
|
||||
private InsetsState getInsetsForTypeAndWindowingMode(@InternalInsetsType int type,
|
||||
@WindowingMode int windowingMode, boolean isAlwaysOnTop) {
|
||||
private InsetsState getInsetsForDispatchInner(@InternalInsetsType int type,
|
||||
@WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme) {
|
||||
InsetsState state = mState;
|
||||
|
||||
if (type != ITYPE_INVALID) {
|
||||
@@ -158,6 +169,11 @@ class InsetsStateController {
|
||||
state.removeSource(ITYPE_NAVIGATION_BAR);
|
||||
}
|
||||
|
||||
if (aboveIme) {
|
||||
state = new InsetsState(state);
|
||||
state.removeSource(ITYPE_IME);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
@@ -607,6 +607,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
*/
|
||||
boolean mSeamlesslyRotated = false;
|
||||
|
||||
/**
|
||||
* Indicates if this window is behind IME. Only windows behind IME can get insets from IME.
|
||||
*/
|
||||
boolean mBehindIme = false;
|
||||
|
||||
/**
|
||||
* Surface insets from the previous call to relayout(), used to track
|
||||
* if we are changing the Surface insets.
|
||||
|
||||
@@ -19,10 +19,12 @@ package com.android.server.wm;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
|
||||
import static android.view.InsetsState.ITYPE_IME;
|
||||
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
||||
import static android.view.InsetsState.ITYPE_STATUS_BAR;
|
||||
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
|
||||
|
||||
@@ -146,6 +148,61 @@ public class InsetsStateControllerTest extends WindowTestsBase {
|
||||
assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStripForDispatch_belowIme() {
|
||||
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
|
||||
final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
|
||||
|
||||
getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
|
||||
|
||||
assertNotNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStripForDispatch_aboveIme() {
|
||||
final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
|
||||
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
|
||||
|
||||
getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
|
||||
|
||||
assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStripForDispatch_childWindow_altFocusable() {
|
||||
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
|
||||
|
||||
final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
|
||||
child.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
|
||||
|
||||
final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
|
||||
|
||||
// IME cannot be the IME target.
|
||||
ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
|
||||
|
||||
getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
|
||||
|
||||
assertNull(getController().getInsetsForDispatch(child).peekSource(ITYPE_IME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStripForDispatch_childWindow_splitScreen() {
|
||||
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
|
||||
|
||||
final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
|
||||
child.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
|
||||
child.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
|
||||
|
||||
final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
|
||||
|
||||
// IME cannot be the IME target.
|
||||
ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
|
||||
|
||||
getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
|
||||
|
||||
assertNull(getController().getInsetsForDispatch(child).peekSource(ITYPE_IME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImeForDispatch() {
|
||||
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
|
||||
|
||||
Reference in New Issue
Block a user