Make display frame compatible

The display frame is used to limit the windows boundary. The frame is
the same as the parent frame in most cases if the window is not
attched. However, if a window doesn't have any layout related
window/sysui flags and the soft input mode is not ADJUST_RESIZE, the
display frame doesn't need to be inset by IME (but the parent frame
does).

Fix: 163435784
Test: atest ViewRootImplTest DisplayPolicyLayoutTests
Merged-In: Ia61933120027642d1f0e0a490546071ca2b6c853
Change-Id: Ia61933120027642d1f0e0a490546071ca2b6c853
This commit is contained in:
Tiger Huang
2020-08-27 21:49:06 +08:00
parent 6a1829d14a
commit 677078e872
6 changed files with 61 additions and 15 deletions

View File

@@ -53,6 +53,9 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CO
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
@@ -1449,11 +1452,10 @@ public final class ViewRootImpl implements ViewParent,
}
// Don't lose the mode we last auto-computed.
if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
if ((attrs.softInputMode & SOFT_INPUT_MASK_ADJUST)
== WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
& ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
| (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
& ~SOFT_INPUT_MASK_ADJUST) | (oldSoftInputMode & SOFT_INPUT_MASK_ADJUST);
}
if (mWindowAttributes.softInputMode != oldSoftInputMode) {
@@ -2073,6 +2075,7 @@ public final class ViewRootImpl implements ViewParent,
final int sysUiVis = inOutParams.systemUiVisibility | inOutParams.subtreeSystemUiVisibility;
final int flags = inOutParams.flags;
final int type = inOutParams.type;
final int adjust = inOutParams.softInputMode & SOFT_INPUT_MASK_ADJUST;
if ((inOutParams.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) {
inOutParams.insetsFlags.appearance = 0;
@@ -2098,12 +2101,13 @@ public final class ViewRootImpl implements ViewParent,
}
}
inOutParams.privateFlags &= ~PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
if ((inOutParams.privateFlags & PRIVATE_FLAG_FIT_INSETS_CONTROLLED) != 0) {
return;
}
int types = inOutParams.getFitInsetsTypes();
int sides = inOutParams.getFitInsetsSides();
boolean ignoreVis = inOutParams.isFitInsetsIgnoringVisibility();
if (((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0
@@ -2118,10 +2122,13 @@ public final class ViewRootImpl implements ViewParent,
if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
ignoreVis = true;
} else if ((types & Type.systemBars()) == Type.systemBars()) {
types |= Type.ime();
if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
types |= Type.ime();
} else {
inOutParams.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
}
}
inOutParams.setFitInsetsTypes(types);
inOutParams.setFitInsetsSides(sides);
inOutParams.setFitInsetsIgnoringVisibility(ignoreVis);
// The fitting of insets are not really controlled by the clients, so we remove the flag.
@@ -2491,8 +2498,7 @@ public final class ViewRootImpl implements ViewParent,
if (mFirst || mAttachInfo.mViewVisibilityChanged) {
mAttachInfo.mViewVisibilityChanged = false;
int resizeMode = mSoftInputMode &
WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
int resizeMode = mSoftInputMode & SOFT_INPUT_MASK_ADJUST;
// If we are in auto resize mode, then we need to determine
// what mode to use now.
if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
@@ -2505,11 +2511,8 @@ public final class ViewRootImpl implements ViewParent,
if (resizeMode == 0) {
resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
}
if ((lp.softInputMode &
WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
lp.softInputMode = (lp.softInputMode &
~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
resizeMode;
if ((lp.softInputMode & SOFT_INPUT_MASK_ADJUST) != resizeMode) {
lp.softInputMode = (lp.softInputMode & ~SOFT_INPUT_MASK_ADJUST) | resizeMode;
params = lp;
}
}

View File

@@ -2032,6 +2032,12 @@ public interface WindowManager extends ViewManager {
*/
public static final int PRIVATE_FLAG_FIT_INSETS_CONTROLLED = 0x10000000;
/**
* Flag to indicate that the parent frame of a window should be inset by IME.
* @hide
*/
public static final int PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME = 0x40000000;
/**
* An internal annotation for flags that can be specified to {@link #softInputMode}.
*

View File

@@ -24,6 +24,7 @@ import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -117,7 +118,15 @@ public class ViewRootImplTest {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
// A window which fits system bars must fit IME, unless its type is toast or system alert.
assertEquals(Type.systemBars(), attrs.getFitInsetsTypes());
}
@Test
public void adjustLayoutParamsForCompatibility_fitSystemBarsAndIme() {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
attrs.softInputMode |= SOFT_INPUT_ADJUST_RESIZE;
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
assertEquals(Type.systemBars() | Type.ime(), attrs.getFitInsetsTypes());
}

View File

@@ -29,6 +29,7 @@ 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;
@@ -71,6 +72,7 @@ import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_M
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
@@ -2191,6 +2193,13 @@ public class DisplayPolicy {
df.set(left, top, dfu.right - right, dfu.bottom - bottom);
if (attached == null) {
pf.set(df);
if ((pfl & PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME) != 0) {
final InsetsSource source = mDisplayContent.getInsetsPolicy()
.getInsetsForDispatch(win).peekSource(ITYPE_IME);
if (source != null) {
pf.inset(source.calculateInsets(pf, false /* ignoreVisibility */));
}
}
vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
? displayFrames.mCurrent : displayFrames.mDock);
} else {

View File

@@ -36,6 +36,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -348,6 +349,24 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@Test
public void layoutWindowLw_insetParentFrameByIme() {
final InsetsState state =
mDisplayContent.getInsetsStateController().getRawInsetsState();
state.getSource(InsetsState.ITYPE_IME).setVisible(true);
state.getSource(InsetsState.ITYPE_IME).setFrame(
0, DISPLAY_HEIGHT - IME_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT);
mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
mWindow.mBehindIme = true;
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, IME_HEIGHT);
}
@Test
public void layoutWindowLw_fitDisplayCutout() {
addDisplayCutout();

View File

@@ -62,7 +62,7 @@ public class DisplayPolicyTestsBase extends WindowTestsBase {
static final int STATUS_BAR_HEIGHT = 10;
static final int NAV_BAR_HEIGHT = 15;
static final int DISPLAY_CUTOUT_HEIGHT = 8;
static final int INPUT_METHOD_WINDOW_TOP = 585;
static final int IME_HEIGHT = 415;
DisplayPolicy mDisplayPolicy;