diff options
| author | 2023-12-08 07:07:27 +0000 | |
|---|---|---|
| committer | 2023-12-08 07:07:27 +0000 | |
| commit | 43a268fbfdc6d025451c32b51b8fbadfdead3d4e (patch) | |
| tree | db71e926f69afa180cf47f23362c22157f2a6772 | |
| parent | bdd1caebf987f636339aa7992cb328b8c333493f (diff) | |
| parent | f6f102cc8d209eafce40e4749fbf031cb568ee8f (diff) | |
Merge "Add PRIVATE_FLAG_CONSUME_IME_INSETS" into main
5 files changed, 117 insertions, 9 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 046ea77f196d..8a37c7c1ef09 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -3251,6 +3251,13 @@ public interface WindowManager extends ViewManager { public static final int PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC = 1 << 24; /** + * Flag to indicate that the window consumes the insets of {@link Type#ime()}. This makes + * windows below this window unable to receive visible IME insets. + * @hide + */ + public static final int PRIVATE_FLAG_CONSUME_IME_INSETS = 1 << 25; + + /** * Flag to indicate that the window is controlling the appearance of system bars. So we * don't need to adjust it by reading its system UI flags for compatibility. * @hide @@ -3334,6 +3341,7 @@ public interface WindowManager extends ViewManager { PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION, PRIVATE_FLAG_NOT_MAGNIFIABLE, PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC, + PRIVATE_FLAG_CONSUME_IME_INSETS, PRIVATE_FLAG_APPEARANCE_CONTROLLED, PRIVATE_FLAG_BEHAVIOR_CONTROLLED, PRIVATE_FLAG_FIT_INSETS_CONTROLLED, @@ -3432,6 +3440,10 @@ public interface WindowManager extends ViewManager { equals = PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC, name = "COLOR_SPACE_AGNOSTIC"), @ViewDebug.FlagToString( + mask = PRIVATE_FLAG_CONSUME_IME_INSETS, + equals = PRIVATE_FLAG_CONSUME_IME_INSETS, + name = "CONSUME_IME_INSETS"), + @ViewDebug.FlagToString( mask = PRIVATE_FLAG_APPEARANCE_CONTROLLED, equals = PRIVATE_FLAG_APPEARANCE_CONTROLLED, name = "APPEARANCE_CONTROLLED"), @@ -3458,7 +3470,7 @@ public interface WindowManager extends ViewManager { @ViewDebug.FlagToString( mask = PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY, equals = PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY, - name = "PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY") + name = "SYSTEM_APPLICATION_OVERLAY") }) @PrivateFlags @TestApi diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index b862d7c28b52..460a68f48ff6 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -39,6 +39,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCRE import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_CONSUME_IME_INSETS; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP; @@ -272,6 +273,8 @@ public class DisplayPolicy { private @InsetsType int mForciblyShownTypes; + private boolean mImeInsetsConsumed; + private boolean mIsImmersiveMode; // The windows we were told about in focusChanged. @@ -1420,6 +1423,7 @@ public class DisplayPolicy { mShowingDream = false; mIsFreeformWindowOverlappingWithNavBar = false; mForciblyShownTypes = 0; + mImeInsetsConsumed = false; } /** @@ -1481,6 +1485,17 @@ public class DisplayPolicy { mForciblyShownTypes |= win.mAttrs.forciblyShownTypes; } + if (win.mImeInsetsConsumed != mImeInsetsConsumed) { + win.mImeInsetsConsumed = mImeInsetsConsumed; + final WindowState imeWin = mDisplayContent.mInputMethodWindow; + if (win.isReadyToDispatchInsetsState() && imeWin != null && imeWin.isVisible()) { + win.notifyInsetsChanged(); + } + } + if ((attrs.privateFlags & PRIVATE_FLAG_CONSUME_IME_INSETS) != 0 && win.isVisible()) { + mImeInsetsConsumed = true; + } + if (!affectsSystemUi) { return; } @@ -2828,6 +2843,7 @@ public class DisplayPolicy { } } pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen); + pw.print(prefix); pw.print("mImeInsetsConsumed="); pw.println(mImeInsetsConsumed); pw.print(prefix); pw.print("mForceShowNavigationBarEnabled="); pw.print(mForceShowNavigationBarEnabled); pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn); diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index c089d107d07d..781567990235 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -391,13 +391,26 @@ class InsetsPolicy { if (originalImeSource != null) { final boolean imeVisibility = w.isRequestedVisible(Type.ime()); - final InsetsState state = copyState ? new InsetsState(originalState) + final InsetsState state = copyState + ? new InsetsState(originalState) : originalState; final InsetsSource imeSource = new InsetsSource(originalImeSource); imeSource.setVisible(imeVisibility); state.addSource(imeSource); return state; } + } else if (w.mImeInsetsConsumed) { + // Set the IME source (if there is one) to be invisible if it has been consumed. + final InsetsSource originalImeSource = originalState.peekSource(ID_IME); + if (originalImeSource != null && originalImeSource.isVisible()) { + final InsetsState state = copyState + ? new InsetsState(originalState) + : originalState; + final InsetsSource imeSource = new InsetsSource(originalImeSource); + imeSource.setVisible(false); + state.addSource(imeSource); + return state; + } } return originalState; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index b890a9e9bd04..c7a7e28cc5eb 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -668,6 +668,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP boolean mSeamlesslyRotated = false; /** + * Whether the IME insets have been consumed. If {@code true}, this window won't be able to + * receive visible IME insets; {@code false}, otherwise. + */ + boolean mImeInsetsConsumed = false; + + /** * The insets state of sources provided by windows above the current window. */ final InsetsState mAboveInsetsState = new InsetsState(); @@ -1487,7 +1493,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (insetsChanged) { mWindowFrames.setInsetsChanged(false); - mWmService.mWindowsInsetsChanged--; + if (mWmService.mWindowsInsetsChanged > 0) { + mWmService.mWindowsInsetsChanged--; + } if (mWmService.mWindowsInsetsChanged == 0) { mWmService.mH.removeMessages(WindowManagerService.H.INSETS_CHANGED); } @@ -3796,13 +3804,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ void notifyInsetsChanged() { ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "notifyInsetsChanged for %s ", this); - mWindowFrames.setInsetsChanged(true); + if (!mWindowFrames.hasInsetsChanged()) { + mWindowFrames.setInsetsChanged(true); - // If the new InsetsState won't be dispatched before releasing WM lock, the following - // message will be executed. - mWmService.mWindowsInsetsChanged++; - mWmService.mH.removeMessages(WindowManagerService.H.INSETS_CHANGED); - mWmService.mH.sendEmptyMessage(WindowManagerService.H.INSETS_CHANGED); + // If the new InsetsState won't be dispatched before releasing WM lock, the following + // message will be executed. + mWmService.mWindowsInsetsChanged++; + mWmService.mH.removeMessages(WindowManagerService.H.INSETS_CHANGED); + mWmService.mH.sendEmptyMessage(WindowManagerService.H.INSETS_CHANGED); + } final WindowContainer p = getParent(); if (p != null) { @@ -4192,6 +4202,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } else { pw.print("null"); } + pw.println(); if (mXOffset != 0 || mYOffset != 0) { pw.println(prefix + "mXOffset=" + mXOffset + " mYOffset=" + mYOffset); @@ -4225,6 +4236,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (computeDragResizing()) { pw.println(prefix + "computeDragResizing=" + computeDragResizing()); } + if (mImeInsetsConsumed) { + pw.println(prefix + "mImeInsetsConsumed=true"); + } pw.println(prefix + "isOnScreen=" + isOnScreen()); pw.println(prefix + "isVisible=" + isVisible()); pw.println(prefix + "keepClearAreas: restricted=" + mKeepClearAreas diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java index ffa1ed926766..38a66a9d5486 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java @@ -19,10 +19,13 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static android.view.InsetsSource.ID_IME; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_CONSUME_IME_INSETS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; @@ -432,6 +435,56 @@ public class InsetsPolicyTest extends WindowTestsBase { } + @SetupWindows(addWindows = W_INPUT_METHOD) + @Test + public void testConsumeImeInsets() { + final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); + final InsetsSource imeSource = new InsetsSource(ID_IME, ime()); + imeSource.setVisible(true); + mImeWindow.mHasSurface = true; + + final WindowState win1 = addWindow(TYPE_APPLICATION, "win1"); + final WindowState win2 = addWindow(TYPE_APPLICATION, "win2"); + + win1.mAboveInsetsState.addSource(imeSource); + win1.mHasSurface = true; + win2.mAboveInsetsState.addSource(imeSource); + win2.mHasSurface = true; + + assertTrue(mImeWindow.isVisible()); + assertTrue(win1.isVisible()); + assertTrue(win2.isVisible()); + + // Make sure both windows have visible IME insets. + assertTrue(win1.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime())); + assertTrue(win2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime())); + + win2.mAttrs.privateFlags |= PRIVATE_FLAG_CONSUME_IME_INSETS; + + displayPolicy.beginPostLayoutPolicyLw(); + displayPolicy.applyPostLayoutPolicyLw(win2, win2.mAttrs, null, null); + displayPolicy.applyPostLayoutPolicyLw(win1, win1.mAttrs, null, null); + displayPolicy.finishPostLayoutPolicyLw(); + + // Make sure win2 doesn't have visible IME insets, but win1 still does. + assertTrue(win2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime())); + assertFalse(win1.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime())); + assertTrue(win1.getWindowFrames().hasInsetsChanged()); + + win2.mAttrs.privateFlags &= ~PRIVATE_FLAG_CONSUME_IME_INSETS; + win2.getWindowFrames().setInsetsChanged(false); + + displayPolicy.beginPostLayoutPolicyLw(); + displayPolicy.applyPostLayoutPolicyLw(win2, win2.mAttrs, null, null); + displayPolicy.applyPostLayoutPolicyLw(win1, win1.mAttrs, null, null); + displayPolicy.finishPostLayoutPolicyLw(); + + // Make sure both windows have visible IME insets. + assertTrue(win1.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime())); + assertTrue(win2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime())); + assertTrue(win1.getWindowFrames().hasInsetsChanged()); + } + private WindowState addNavigationBar() { final Binder owner = new Binder(); final WindowState win = createWindow(null, TYPE_NAVIGATION_BAR, "navBar"); |