diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index c50048eeab642..857467208b6ea 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1244,6 +1244,11 @@ class DisplayContent extends WindowContainer frameProvider){ + setInsetProvider(type, win, frameProvider, null /* imeFrameProvider */); + } + /** * Marks a window as providing insets for the rest of the windows in the system. * @@ -1251,10 +1256,14 @@ class DisplayContent extends WindowContainer frameProvider) { - mInsetsStateController.getSourceProvider(type).setWindow(win, frameProvider); + @Nullable TriConsumer frameProvider, + @Nullable TriConsumer imeFrameProvider) { + mInsetsStateController.getSourceProvider(type).setWindow(win, frameProvider, + imeFrameProvider); } InsetsStateController getInsetsStateController() { @@ -3283,7 +3292,7 @@ class DisplayContent extends WindowContainer + inOutFrame.set(windowState.getFrameLw())); + mDisplayContent.setInsetProvider(ITYPE_BOTTOM_GESTURES, win, (displayFrames, windowState, inOutFrame) -> { inOutFrame.top -= mBottomGestureAdditionalInset; diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 2bb58ddc5b387..d540179a94918 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -34,6 +34,7 @@ import android.util.proto.ProtoOutputStream; import android.view.InsetsSource; import android.view.InsetsSourceControl; import android.view.InsetsState; +import android.view.InsetsState.InternalInsetsType; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; @@ -61,6 +62,8 @@ class InsetsSourceProvider { private @Nullable ControlAdapter mAdapter; private TriConsumer mFrameProvider; + private TriConsumer mImeFrameProvider; + private final Rect mImeOverrideFrame = new Rect(); /** The visibility override from the current controlling window. */ private boolean mClientVisible; @@ -111,9 +114,12 @@ class InsetsSourceProvider { * @param win The window that links to this source. * @param frameProvider Based on display frame state and the window, calculates the resulting * frame that should be reported to clients. + * @param imeFrameProvider Based on display frame state and the window, calculates the resulting + * frame that should be reported to IME. */ void setWindow(@Nullable WindowState win, - @Nullable TriConsumer frameProvider) { + @Nullable TriConsumer frameProvider, + @Nullable TriConsumer imeFrameProvider) { if (mWin != null) { if (mControllable) { mWin.setControllableInsetProvider(null); @@ -126,6 +132,7 @@ class InsetsSourceProvider { } mWin = win; mFrameProvider = frameProvider; + mImeFrameProvider = imeFrameProvider; if (win == null) { setServerVisible(false); mSource.setFrame(new Rect()); @@ -162,6 +169,12 @@ class InsetsSourceProvider { } mSource.setFrame(mTmpRect); + if (mImeFrameProvider != null) { + mImeOverrideFrame.set(mWin.getFrameLw()); + mImeFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, + mImeOverrideFrame); + } + if (mWin.mGivenVisibleInsets.left != 0 || mWin.mGivenVisibleInsets.top != 0 || mWin.mGivenVisibleInsets.right != 0 || mWin.mGivenVisibleInsets.bottom != 0) { mTmpRect.set(mWin.getFrameLw()); @@ -303,6 +316,21 @@ class InsetsSourceProvider { return sNewInsetsMode == NEW_INSETS_MODE_NONE || mClientVisible; } + /** + * @return Whether this provider uses a different frame to dispatch to the IME. + */ + boolean overridesImeFrame() { + return mImeFrameProvider != null; + } + + /** + * @return Rect to dispatch to the IME as frame. Only valid if {@link #overridesImeFrame()} + * returns {@code true}. + */ + Rect getImeOverrideFrame() { + return mImeOverrideFrame; + } + private class ControlAdapter implements AnimationAdapter { private SurfaceControl mCapturedLeash; diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index b2234d17984e4..3e698da13097a 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -88,6 +88,20 @@ class InsetsStateController { state.removeSource(ITYPE_IME); state.removeSource(ITYPE_STATUS_BAR); } + + // IME needs different frames for certain cases (e.g. navigation bar in gesture nav). + if (type == ITYPE_IME) { + for (int i = mProviders.size() - 1; i >= 0; i--) { + InsetsSourceProvider otherProvider = mProviders.valueAt(i); + if (otherProvider.overridesImeFrame()) { + InsetsSource override = + new InsetsSource(state.getSource(otherProvider.getSource().getType())); + override.setFrame(otherProvider.getImeOverrideFrame()); + state.addSource(override); + } + } + } + return state; } diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java index d819b1ada6592..7ffdd7cdceb61 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -57,7 +57,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); statusBar.getFrameLw().set(0, 0, 500, 100); statusBar.mHasSurface = true; - mProvider.setWindow(statusBar, null); + mProvider.setWindow(statusBar, null, null); mProvider.onPostLayout(); assertEquals(new Rect(0, 0, 500, 100), mProvider.getSource().getFrame()); assertEquals(Insets.of(0, 100, 0, 0), @@ -74,7 +74,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { ime.getGivenContentInsetsLw().set(0, 0, 0, 60); ime.getGivenVisibleInsetsLw().set(0, 0, 0, 75); ime.mHasSurface = true; - mProvider.setWindow(ime, null); + mProvider.setWindow(ime, null, null); mProvider.onPostLayout(); assertEquals(new Rect(0, 0, 500, 40), mProvider.getSource().getFrame()); assertEquals(new Rect(0, 0, 500, 25), mProvider.getSource().getVisibleFrame()); @@ -89,7 +89,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { public void testPostLayout_invisible() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); statusBar.getFrameLw().set(0, 0, 500, 100); - mProvider.setWindow(statusBar, null); + mProvider.setWindow(statusBar, null, null); mProvider.onPostLayout(); assertEquals(Insets.NONE, mProvider.getSource().calculateInsets(new Rect(0, 0, 500, 500), false /* ignoreVisibility */)); @@ -102,7 +102,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { mProvider.setWindow(statusBar, (displayFrames, windowState, rect) -> { rect.set(10, 10, 20, 20); - }); + }, null); mProvider.onPostLayout(); assertEquals(new Rect(10, 10, 20, 20), mProvider.getSource().getFrame()); } @@ -112,7 +112,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); statusBar.getFrameLw().set(0, 0, 500, 100); - mProvider.setWindow(statusBar, null); + mProvider.setWindow(statusBar, null, null); mProvider.updateControlForTarget(target, false /* force */); assertNotNull(mProvider.getControl(target)); mProvider.updateControlForTarget(null, false /* force */); @@ -124,7 +124,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); statusBar.getFrameLw().set(0, 0, 500, 100); - mProvider.setWindow(statusBar, null); + mProvider.setWindow(statusBar, null, null); mProvider.updateControlForFakeTarget(target); assertNotNull(mProvider.getControl(target)); assertNull(mProvider.getControl(target).getLeash()); @@ -137,7 +137,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); statusBar.getFrameLw().set(0, 0, 500, 100); - mProvider.setWindow(statusBar, null); + mProvider.setWindow(statusBar, null, null); mProvider.updateControlForTarget(target, false /* force */); InsetsState state = new InsetsState(); state.getSource(ITYPE_STATUS_BAR).setVisible(false); @@ -150,7 +150,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); statusBar.getFrameLw().set(0, 0, 500, 100); - mProvider.setWindow(statusBar, null); + mProvider.setWindow(statusBar, null, null); InsetsState state = new InsetsState(); state.getSource(ITYPE_STATUS_BAR).setVisible(false); mProvider.onInsetsModified(target, state.getSource(ITYPE_STATUS_BAR)); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index d13baeccb68a3..39cdd2cb907ec 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -21,26 +21,26 @@ 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.TYPE_APPLICATION; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.view.InsetsSource; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.test.InsetsModeSession; -import androidx.test.filters.FlakyTest; -import androidx.test.filters.SmallTest; - import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import androidx.test.filters.FlakyTest; +import androidx.test.filters.SmallTest; + @SmallTest @FlakyTest(detail = "Promote to pre-submit once confirmed stable.") @Presubmit @@ -65,7 +65,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { public void testStripForDispatch_notOwn() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null); + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR)); assertNotNull(getController().getInsetsForDispatch(app).getSource(ITYPE_STATUS_BAR)); } @@ -74,7 +74,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { public void testStripForDispatch_own() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR) - .setWindow(statusBar, null); + .setWindow(statusBar, null, null); statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR)); final InsetsState state = getController().getInsetsForDispatch(statusBar); for (int i = state.getSourcesCount() - 1; i >= 0; i--) { @@ -88,19 +88,36 @@ public class InsetsStateControllerTest extends WindowTestsBase { final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar"); final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime"); - getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null); - getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null); - getController().getSourceProvider(ITYPE_IME).setWindow(ime, null); + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); + getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null); + getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null); assertEquals(0, getController().getInsetsForDispatch(navBar).getSourcesCount()); } + @Test + public void testImeForDispatch() { + final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); + final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime"); + InsetsSourceProvider statusBarProvider = + getController().getSourceProvider(ITYPE_STATUS_BAR); + statusBarProvider.setWindow(statusBar, null, ((displayFrames, windowState, rect) -> + rect.set(0, 1, 2, 3))); + getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null); + statusBar.setControllableInsetProvider(statusBarProvider); + + statusBarProvider.onPostLayout(); + + final InsetsState state = getController().getInsetsForDispatch(ime); + assertEquals(new Rect(0, 1, 2, 3), state.getSource(ITYPE_STATUS_BAR).getFrame()); + } + @Test public void testBarControllingWinChanged() { final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar"); final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null); - getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null); + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); + getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null); getController().onBarControlTargetChanged(app, null, app, null); InsetsSourceControl[] controls = getController().getControlsForDispatch(app); assertEquals(2, controls.length); @@ -110,7 +127,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { public void testControlRevoked() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null); + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); getController().onBarControlTargetChanged(app, null, null, null); assertNotNull(getController().getControlsForDispatch(app)); getController().onBarControlTargetChanged(null, null, null, null); @@ -122,7 +139,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { public void testControlRevoked_animation() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null); + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); getController().onBarControlTargetChanged(app, null, null, null); assertNotNull(getController().getControlsForDispatch(app)); statusBar.cancelAnimation(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 186ff6b1515bd..2c68cc7a19bfd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -425,7 +425,7 @@ public class WindowStateTests extends WindowTestsBase { statusBar.mHasSurface = true; assertTrue(statusBar.isVisible()); mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR) - .setWindow(statusBar, null /* frameProvider */); + .setWindow(statusBar, null /* frameProvider */, null /* imeFrameProvider */); mDisplayContent.getInsetsStateController().onBarControlTargetChanged( app, null /* fakeTopControlling */, app, null /* fakeNavControlling */); final InsetsSource source = new InsetsSource(ITYPE_STATUS_BAR);