diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 3acb127673e97..0b2bd811bb844 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3317,7 +3317,7 @@ class DisplayContent extends WindowContainer getImeSourceFrameProvider() { + return (displayFrames, windowState, inOutFrame) -> { + if (mNavigationBar != null && navigationBarPosition(displayFrames.mDisplayWidth, + displayFrames.mDisplayHeight, + displayFrames.mRotation) == NAV_BAR_BOTTOM) { + // In gesture navigation, nav bar frame is larger than frame to calculate insets. + // IME should not provide frame which is smaller than the nav bar frame. Otherwise, + // nav bar might be overlapped with the content of the client when IME is shown. + sTmpRect.set(inOutFrame); + sTmpRect.intersectUnchecked(mNavigationBar.getFrameLw()); + inOutFrame.inset(windowState.getGivenContentInsetsLw()); + inOutFrame.union(sTmpRect); + } else { + inOutFrame.inset(windowState.getGivenContentInsetsLw()); + } + }; + } + private static void enforceSingleInsetsTypeCorrespondingToWindowType(int[] insetsTypes) { int count = 0; for (int insetsType : insetsTypes) { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java index c2db0c09f88a5..a3f9b2e71cb59 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java @@ -16,7 +16,9 @@ package com.android.server.wm; +import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; +import static android.view.Surface.ROTATION_0; import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @@ -56,7 +58,10 @@ import static org.mockito.Mockito.when; import android.graphics.PixelFormat; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; +import android.view.DisplayInfo; +import android.view.InsetsSource; import android.view.InsetsState; +import android.view.WindowInsets.Side; import android.view.WindowManager; import androidx.test.filters.SmallTest; @@ -352,4 +357,36 @@ public class DisplayPolicyTests extends WindowTestsBase { insetsPolicy.updateBarControlTarget(mAppWindow); assertNull(displayPolicy.mInputConsumer); } + + @Test + public void testImeMinimalSourceFrame() { + final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); + final DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = 1000; + displayInfo.logicalHeight = 2000; + displayInfo.rotation = ROTATION_0; + mDisplayContent.mDisplayFrames = new DisplayFrames(mDisplayContent.getDisplayId(), + displayInfo, null /* displayCutout */); + + displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs); + mNavBarWindow.getControllableInsetProvider().setServerVisible(true); + + mDisplayContent.setInputMethodWindowLocked(mImeWindow); + mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM); + mImeWindow.getGivenContentInsetsLw().set(0, displayInfo.logicalHeight, 0, 0); + mImeWindow.getControllableInsetProvider().setServerVisible(true); + + displayPolicy.beginLayoutLw(mDisplayContent.mDisplayFrames, 0 /* UI mode */); + displayPolicy.layoutWindowLw(mImeWindow, null, mDisplayContent.mDisplayFrames); + + final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState(); + final InsetsSource imeSource = state.peekSource(ITYPE_IME); + final InsetsSource navBarSource = state.peekSource(ITYPE_NAVIGATION_BAR); + + assertNotNull(imeSource); + assertNotNull(navBarSource); + assertFalse(imeSource.getFrame().isEmpty()); + assertFalse(navBarSource.getFrame().isEmpty()); + assertTrue(imeSource.getFrame().contains(navBarSource.getFrame())); + } }