Loading services/core/java/com/android/server/wm/DisplayContent.java +24 −33 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; Loading Loading @@ -141,6 +142,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.WindowConfiguration; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.ScreenOrientation; Loading Loading @@ -3370,34 +3372,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } private boolean isImeControlledByApp() { return mInputMethodTarget != null && !WindowConfiguration.isSplitScreenWindowingMode( mInputMethodTarget.getWindowingMode()); } boolean isImeAttachedToApp() { return (mInputMethodTarget != null && mInputMethodTarget.mActivityRecord != null return isImeControlledByApp() && mInputMethodTarget.mActivityRecord != null && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN // An activity with override bounds should be letterboxed inside its parent bounds, // so it doesn't fill the screen. && mInputMethodTarget.mActivityRecord.matchParentBounds()); } /** * Get IME target that should host IME when this display that is reparented to another * WindowState. * IME is never displayed in a child display. * Use {@link WindowState#getImeControlTarget()} when IME target window * which originally called * {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} is known. * * @return {@link WindowState} of host that controls IME. * {@code null} when {@param dc} is not a virtual display. * @see DisplayContent#reparent */ @Nullable WindowState getImeControlTarget() { WindowState imeTarget = mInputMethodTarget; if (imeTarget != null) { return imeTarget.getImeControlTarget(); } return getInsetsStateController().getImeSourceProvider().getControlTarget().getWindow(); && mInputMethodTarget.mActivityRecord.matchParentBounds(); } /** Loading @@ -3407,7 +3393,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * * @param target current IME target. * @return {@link WindowState} that can host IME. * @see DisplayContent#getImeControlTarget() */ WindowState getImeHostOrFallback(WindowState target) { if (target != null && target.getDisplayContent().canShowIme()) { Loading Loading @@ -3448,8 +3433,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo /** * The IME input target is the window which receives input from IME. It is also a candidate * which controls the visibility and animation of the input method window. * * @param target the window that receives input from IME. */ void setInputMethodInputTarget(WindowState target) { if (mInputMethodInputTarget != target) { Loading @@ -3459,12 +3442,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } private void updateImeControlTarget() { if (!isImeAttachedToApp() && mRemoteInsetsControlTarget != null) { mInputMethodControlTarget = mRemoteInsetsControlTarget; } else { // Otherwise, we just use the ime input target mInputMethodControlTarget = mInputMethodInputTarget; } mInputMethodControlTarget = computeImeControlTarget(); mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget); } Loading @@ -3476,6 +3454,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } /** * Computes the window where we hand IME control to. */ @VisibleForTesting InsetsControlTarget computeImeControlTarget() { if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null) { return mRemoteInsetsControlTarget; } else { // Otherwise, we just use the ime target as received from IME. return mInputMethodInputTarget; } } /** * Computes the window the IME should be attached to. */ Loading services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +68 −21 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; Loading @@ -84,10 +85,13 @@ import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; import android.view.DisplayCutout; import android.view.Gravity; import android.view.IDisplayWindowInsetsController; import android.view.IDisplayWindowRotationCallback; import android.view.IDisplayWindowRotationController; import android.view.ISystemGestureExclusionListener; import android.view.IWindowManager; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.MotionEvent; import android.view.Surface; import android.view.SurfaceControl.Transaction; Loading Loading @@ -810,26 +814,20 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeParent_app() throws Exception { try (final InsetsModeSession session = new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) { final DisplayContent dc = createNewDisplay(); dc.mInputMethodTarget = createWindow(null, TYPE_BASE_APPLICATION, "app"); assertEquals(dc.mInputMethodTarget.mActivityRecord.getSurfaceControl(), dc.computeImeParent()); } } @Test public void testComputeImeParent_app_notFullscreen() throws Exception { try (final InsetsModeSession session = new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) { final DisplayContent dc = createNewDisplay(); dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "app"); dc.mInputMethodTarget.setWindowingMode( WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent()); } } @Test public void testComputeImeParent_app_notMatchParentBounds() { Loading @@ -843,12 +841,61 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeParent_noApp() throws Exception { try (final InsetsModeSession session = new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) { final DisplayContent dc = createNewDisplay(); dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "statusBar"); assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent()); } @Test public void testComputeImeControlTarget() throws Exception { final DisplayContent dc = createNewDisplay(); dc.setRemoteInsetsController(createDisplayWindowInsetsController()); dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app"); dc.mInputMethodTarget = dc.mInputMethodInputTarget; assertEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget()); } @Test public void testComputeImeControlTarget_splitscreen() throws Exception { final DisplayContent dc = createNewDisplay(); dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app"); dc.mInputMethodInputTarget.setWindowingMode( WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); dc.mInputMethodTarget = dc.mInputMethodInputTarget; dc.setRemoteInsetsController(createDisplayWindowInsetsController()); assertNotEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget()); } @Test public void testComputeImeControlTarget_notMatchParentBounds() throws Exception { spyOn(mAppWindow.mActivityRecord); doReturn(false).when(mAppWindow.mActivityRecord).matchParentBounds(); mDisplayContent.mInputMethodInputTarget = mAppWindow; mDisplayContent.mInputMethodTarget = mDisplayContent.mInputMethodInputTarget; mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController()); assertEquals(mAppWindow, mDisplayContent.computeImeControlTarget()); } private IDisplayWindowInsetsController createDisplayWindowInsetsController() { return new IDisplayWindowInsetsController.Stub() { @Override public void insetsChanged(InsetsState insetsState) throws RemoteException { } @Override public void insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] insetsSourceControls) throws RemoteException { } @Override public void showInsets(int i, boolean b) throws RemoteException { } @Override public void hideInsets(int i, boolean b) throws RemoteException { } }; } @Test Loading Loading
services/core/java/com/android/server/wm/DisplayContent.java +24 −33 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; Loading Loading @@ -141,6 +142,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.WindowConfiguration; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.ScreenOrientation; Loading Loading @@ -3370,34 +3372,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } private boolean isImeControlledByApp() { return mInputMethodTarget != null && !WindowConfiguration.isSplitScreenWindowingMode( mInputMethodTarget.getWindowingMode()); } boolean isImeAttachedToApp() { return (mInputMethodTarget != null && mInputMethodTarget.mActivityRecord != null return isImeControlledByApp() && mInputMethodTarget.mActivityRecord != null && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN // An activity with override bounds should be letterboxed inside its parent bounds, // so it doesn't fill the screen. && mInputMethodTarget.mActivityRecord.matchParentBounds()); } /** * Get IME target that should host IME when this display that is reparented to another * WindowState. * IME is never displayed in a child display. * Use {@link WindowState#getImeControlTarget()} when IME target window * which originally called * {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} is known. * * @return {@link WindowState} of host that controls IME. * {@code null} when {@param dc} is not a virtual display. * @see DisplayContent#reparent */ @Nullable WindowState getImeControlTarget() { WindowState imeTarget = mInputMethodTarget; if (imeTarget != null) { return imeTarget.getImeControlTarget(); } return getInsetsStateController().getImeSourceProvider().getControlTarget().getWindow(); && mInputMethodTarget.mActivityRecord.matchParentBounds(); } /** Loading @@ -3407,7 +3393,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * * @param target current IME target. * @return {@link WindowState} that can host IME. * @see DisplayContent#getImeControlTarget() */ WindowState getImeHostOrFallback(WindowState target) { if (target != null && target.getDisplayContent().canShowIme()) { Loading Loading @@ -3448,8 +3433,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo /** * The IME input target is the window which receives input from IME. It is also a candidate * which controls the visibility and animation of the input method window. * * @param target the window that receives input from IME. */ void setInputMethodInputTarget(WindowState target) { if (mInputMethodInputTarget != target) { Loading @@ -3459,12 +3442,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } private void updateImeControlTarget() { if (!isImeAttachedToApp() && mRemoteInsetsControlTarget != null) { mInputMethodControlTarget = mRemoteInsetsControlTarget; } else { // Otherwise, we just use the ime input target mInputMethodControlTarget = mInputMethodInputTarget; } mInputMethodControlTarget = computeImeControlTarget(); mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget); } Loading @@ -3476,6 +3454,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } /** * Computes the window where we hand IME control to. */ @VisibleForTesting InsetsControlTarget computeImeControlTarget() { if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null) { return mRemoteInsetsControlTarget; } else { // Otherwise, we just use the ime target as received from IME. return mInputMethodInputTarget; } } /** * Computes the window the IME should be attached to. */ Loading
services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +68 −21 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; Loading @@ -84,10 +85,13 @@ import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; import android.view.DisplayCutout; import android.view.Gravity; import android.view.IDisplayWindowInsetsController; import android.view.IDisplayWindowRotationCallback; import android.view.IDisplayWindowRotationController; import android.view.ISystemGestureExclusionListener; import android.view.IWindowManager; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.MotionEvent; import android.view.Surface; import android.view.SurfaceControl.Transaction; Loading Loading @@ -810,26 +814,20 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeParent_app() throws Exception { try (final InsetsModeSession session = new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) { final DisplayContent dc = createNewDisplay(); dc.mInputMethodTarget = createWindow(null, TYPE_BASE_APPLICATION, "app"); assertEquals(dc.mInputMethodTarget.mActivityRecord.getSurfaceControl(), dc.computeImeParent()); } } @Test public void testComputeImeParent_app_notFullscreen() throws Exception { try (final InsetsModeSession session = new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) { final DisplayContent dc = createNewDisplay(); dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "app"); dc.mInputMethodTarget.setWindowingMode( WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent()); } } @Test public void testComputeImeParent_app_notMatchParentBounds() { Loading @@ -843,12 +841,61 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeParent_noApp() throws Exception { try (final InsetsModeSession session = new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) { final DisplayContent dc = createNewDisplay(); dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "statusBar"); assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent()); } @Test public void testComputeImeControlTarget() throws Exception { final DisplayContent dc = createNewDisplay(); dc.setRemoteInsetsController(createDisplayWindowInsetsController()); dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app"); dc.mInputMethodTarget = dc.mInputMethodInputTarget; assertEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget()); } @Test public void testComputeImeControlTarget_splitscreen() throws Exception { final DisplayContent dc = createNewDisplay(); dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app"); dc.mInputMethodInputTarget.setWindowingMode( WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); dc.mInputMethodTarget = dc.mInputMethodInputTarget; dc.setRemoteInsetsController(createDisplayWindowInsetsController()); assertNotEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget()); } @Test public void testComputeImeControlTarget_notMatchParentBounds() throws Exception { spyOn(mAppWindow.mActivityRecord); doReturn(false).when(mAppWindow.mActivityRecord).matchParentBounds(); mDisplayContent.mInputMethodInputTarget = mAppWindow; mDisplayContent.mInputMethodTarget = mDisplayContent.mInputMethodInputTarget; mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController()); assertEquals(mAppWindow, mDisplayContent.computeImeControlTarget()); } private IDisplayWindowInsetsController createDisplayWindowInsetsController() { return new IDisplayWindowInsetsController.Stub() { @Override public void insetsChanged(InsetsState insetsState) throws RemoteException { } @Override public void insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] insetsSourceControls) throws RemoteException { } @Override public void showInsets(int i, boolean b) throws RemoteException { } @Override public void hideInsets(int i, boolean b) throws RemoteException { } }; } @Test Loading