From 77414fab19697d88f146ac8a1a68057b147554ad Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Fri, 15 May 2020 18:22:00 +0800 Subject: [PATCH] Make IME source frame not smaller than nav bar frame 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. Fix: 142218188 Test: atest DisplayPolicyTests Change-Id: Ie5edcd1a0f73440623e85aa4a020d16b4266f747 --- .../com/android/server/wm/DisplayContent.java | 2 +- .../com/android/server/wm/DisplayPolicy.java | 18 +++++++++ .../android/server/wm/DisplayPolicyTests.java | 37 +++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) 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())); + } }