Merge "Don't dispatch IME insets if the target is above IME" into rvc-dev

This commit is contained in:
TreeHugger Robot
2020-03-25 17:01:33 +00:00
committed by Android (Google) Code Review
5 changed files with 100 additions and 17 deletions

View File

@@ -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 */);

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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");