Merge "Don't dispatch IME insets if the target is above IME" into rvc-dev am: 0e503e5ebb
Change-Id: I51455b4b2ce3c5c2c5d7f7ef85f24f46cf2c2ef7
This commit is contained in:
@@ -659,6 +659,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
|||||||
// When non-null, new tasks get put into this root task.
|
// When non-null, new tasks get put into this root task.
|
||||||
Task mLaunchRootTask = null;
|
Task mLaunchRootTask = null;
|
||||||
|
|
||||||
|
// Used in performing layout
|
||||||
|
private boolean mTmpWindowsBehindIme;
|
||||||
|
|
||||||
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
|
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
|
||||||
WindowStateAnimator winAnimator = w.mWinAnimator;
|
WindowStateAnimator winAnimator = w.mWinAnimator;
|
||||||
final ActivityRecord activity = w.mActivityRecord;
|
final ActivityRecord activity = w.mActivityRecord;
|
||||||
@@ -750,6 +753,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
|||||||
+ " parentHidden=" + w.isParentWindowHidden());
|
+ " 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
|
// 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,
|
// 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").
|
// since that means "perform layout as normal, just don't display").
|
||||||
@@ -4016,6 +4025,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
|||||||
mTmpWindow = null;
|
mTmpWindow = null;
|
||||||
mTmpInitial = initial;
|
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).
|
// First perform layout of any root windows (not attached to another window).
|
||||||
forAllWindows(mPerformLayout, true /* traverseTopToBottom */);
|
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_GESTURES;
|
||||||
import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
|
import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
|
||||||
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
|
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_DISPLAY_CUTOUT;
|
||||||
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
|
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
|
||||||
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
||||||
@@ -1493,14 +1492,8 @@ public class DisplayPolicy {
|
|||||||
*/
|
*/
|
||||||
public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
|
public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
|
||||||
displayFrames.onBeginLayout();
|
displayFrames.onBeginLayout();
|
||||||
final InsetsState insetsState =
|
updateInsetsStateForDisplayCutout(displayFrames,
|
||||||
mDisplayContent.getInsetsStateController().getRawInsetsState();
|
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);
|
|
||||||
mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
|
mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
|
||||||
mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
|
mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
|
||||||
|
|
||||||
|
|||||||
@@ -88,8 +88,8 @@ class InsetsStateController {
|
|||||||
final InsetsSourceProvider provider = target.getControllableInsetProvider();
|
final InsetsSourceProvider provider = target.getControllableInsetProvider();
|
||||||
final @InternalInsetsType int type = provider != null
|
final @InternalInsetsType int type = provider != null
|
||||||
? provider.getSource().getType() : ITYPE_INVALID;
|
? provider.getSource().getType() : ITYPE_INVALID;
|
||||||
return getInsetsForTypeAndWindowingMode(type, target.getWindowingMode(),
|
return getInsetsForDispatchInner(type, target.getWindowingMode(), target.isAlwaysOnTop(),
|
||||||
target.isAlwaysOnTop());
|
isAboveIme(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
|
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
|
||||||
@@ -97,13 +97,24 @@ class InsetsStateController {
|
|||||||
final WindowToken token = mDisplayContent.getWindowToken(attrs.token);
|
final WindowToken token = mDisplayContent.getWindowToken(attrs.token);
|
||||||
final @WindowingMode int windowingMode = token != null
|
final @WindowingMode int windowingMode = token != null
|
||||||
? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
|
? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
|
||||||
final boolean alwaysOnTop = token != null
|
final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
|
||||||
? token.isAlwaysOnTop() : false;
|
return getInsetsForDispatchInner(type, windowingMode, alwaysOnTop, isAboveIme(token));
|
||||||
return getInsetsForTypeAndWindowingMode(type, windowingMode, alwaysOnTop);
|
}
|
||||||
|
|
||||||
|
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) {
|
private static @InternalInsetsType int getInsetsTypeForWindowType(int type) {
|
||||||
switch(type) {
|
switch (type) {
|
||||||
case TYPE_STATUS_BAR:
|
case TYPE_STATUS_BAR:
|
||||||
return ITYPE_STATUS_BAR;
|
return ITYPE_STATUS_BAR;
|
||||||
case TYPE_NAVIGATION_BAR:
|
case TYPE_NAVIGATION_BAR:
|
||||||
@@ -116,8 +127,8 @@ class InsetsStateController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @see #getInsetsForDispatch */
|
/** @see #getInsetsForDispatch */
|
||||||
private InsetsState getInsetsForTypeAndWindowingMode(@InternalInsetsType int type,
|
private InsetsState getInsetsForDispatchInner(@InternalInsetsType int type,
|
||||||
@WindowingMode int windowingMode, boolean isAlwaysOnTop) {
|
@WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme) {
|
||||||
InsetsState state = mState;
|
InsetsState state = mState;
|
||||||
|
|
||||||
if (type != ITYPE_INVALID) {
|
if (type != ITYPE_INVALID) {
|
||||||
@@ -158,6 +169,11 @@ class InsetsStateController {
|
|||||||
state.removeSource(ITYPE_NAVIGATION_BAR);
|
state.removeSource(ITYPE_NAVIGATION_BAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aboveIme) {
|
||||||
|
state = new InsetsState(state);
|
||||||
|
state.removeSource(ITYPE_IME);
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -607,6 +607,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
|||||||
*/
|
*/
|
||||||
boolean mSeamlesslyRotated = false;
|
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
|
* Surface insets from the previous call to relayout(), used to track
|
||||||
* if we are changing the Surface insets.
|
* 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_FREEFORM;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
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_IME;
|
||||||
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
||||||
import static android.view.InsetsState.ITYPE_STATUS_BAR;
|
import static android.view.InsetsState.ITYPE_STATUS_BAR;
|
||||||
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
|
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.FLAG_NOT_FOCUSABLE;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
|
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));
|
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
|
@Test
|
||||||
public void testImeForDispatch() {
|
public void testImeForDispatch() {
|
||||||
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
|
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
|
||||||
|
|||||||
Reference in New Issue
Block a user