Loading services/core/java/com/android/server/wm/InsetsPolicy.java +36 −10 Original line number Diff line number Diff line Loading @@ -30,6 +30,10 @@ import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_B import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.StatusBarManager; Loading Loading @@ -211,7 +215,7 @@ class InsetsPolicy { InsetsState getInsetsForWindow(WindowState target) { final InsetsState originalState = mStateController.getInsetsForWindow(target); final InsetsState state = adjustVisibilityForTransientTypes(originalState); return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state; return adjustVisibilityForIme(target, state, state == originalState); } /** Loading Loading @@ -241,17 +245,39 @@ class InsetsPolicy { return state; } // Navigation bar insets is always visible to IME. private static InsetsState adjustVisibilityForIme(InsetsState originalState, private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState, boolean copyState) { if (w.mIsImWindow) { // Navigation bar insets is always visible to IME. final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR); if (originalNavSource != null && !originalNavSource.isVisible()) { final InsetsState state = copyState ? new InsetsState(originalState) : originalState; final InsetsState state = copyState ? new InsetsState(originalState) : originalState; final InsetsSource navSource = new InsetsSource(originalNavSource); navSource.setVisible(true); state.addSource(navSource); return state; } } else if (w.mActivityRecord != null && !w.mActivityRecord.mLastImeShown) { // During switching tasks with gestural navigation, if the IME is attached to // one app window on that time, even the next app window is behind the IME window, // conceptually the window should not receive the IME insets if the next window is // not eligible IME requester and ready to show IME on top of it. final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp(); final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME); if (originalImeSource != null && shouldImeAttachedToApp && (w.isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS) || !w.getRequestedVisibility(ITYPE_IME))) { final InsetsState state = copyState ? new InsetsState(originalState) : originalState; final InsetsSource imeSource = new InsetsSource(originalImeSource); imeSource.setVisible(false); state.addSource(imeSource); return state; } } return originalState; } Loading services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +33 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL; import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowContainer.SYNC_STATE_WAITING_FOR_DRAW; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -891,6 +894,36 @@ public class WindowStateTests extends WindowTestsBase { assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)); } @UseTestDisplay(addWindows = W_INPUT_METHOD) @Test public void testAdjustImeInsetsVisibilityWhenTaskSwitchIsAnimating() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2"); final InsetsStateController controller = mDisplayContent.getInsetsStateController(); controller.getImeSourceProvider().setWindow(mImeWindow, null, null); // Simulate app requests IME with updating all windows Insets State when IME is above app. mDisplayContent.setImeLayeringTarget(app); mDisplayContent.setImeInputTarget(app); assertTrue(mDisplayContent.shouldImeAttachedToApp()); controller.getImeSourceProvider().scheduleShowImePostLayout(app); controller.getImeSourceProvider().getSource().setVisible(true); controller.updateAboveInsetsState(mImeWindow, false); // Simulate task switching animation happens when switching app to app2. spyOn(app); spyOn(app2); doReturn(true).when(app).isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS); doReturn(true).when(app2).isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS); app.mActivityRecord.mLastImeShown = true; // Verify the IME insets is visible on app, but not for app2 during task animating. InsetsState stateApp = app.getInsetsState(); InsetsState stateApp2 = app2.getInsetsState(); assertTrue(stateApp.getSource(ITYPE_IME).isVisible()); assertFalse(stateApp2.getSource(ITYPE_IME).isVisible()); } @UseTestDisplay(addWindows = { W_ACTIVITY }) @Test public void testUpdateImeControlTargetWhenLeavingMultiWindow() { Loading Loading
services/core/java/com/android/server/wm/InsetsPolicy.java +36 −10 Original line number Diff line number Diff line Loading @@ -30,6 +30,10 @@ import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_B import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.StatusBarManager; Loading Loading @@ -211,7 +215,7 @@ class InsetsPolicy { InsetsState getInsetsForWindow(WindowState target) { final InsetsState originalState = mStateController.getInsetsForWindow(target); final InsetsState state = adjustVisibilityForTransientTypes(originalState); return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state; return adjustVisibilityForIme(target, state, state == originalState); } /** Loading Loading @@ -241,17 +245,39 @@ class InsetsPolicy { return state; } // Navigation bar insets is always visible to IME. private static InsetsState adjustVisibilityForIme(InsetsState originalState, private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState, boolean copyState) { if (w.mIsImWindow) { // Navigation bar insets is always visible to IME. final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR); if (originalNavSource != null && !originalNavSource.isVisible()) { final InsetsState state = copyState ? new InsetsState(originalState) : originalState; final InsetsState state = copyState ? new InsetsState(originalState) : originalState; final InsetsSource navSource = new InsetsSource(originalNavSource); navSource.setVisible(true); state.addSource(navSource); return state; } } else if (w.mActivityRecord != null && !w.mActivityRecord.mLastImeShown) { // During switching tasks with gestural navigation, if the IME is attached to // one app window on that time, even the next app window is behind the IME window, // conceptually the window should not receive the IME insets if the next window is // not eligible IME requester and ready to show IME on top of it. final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp(); final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME); if (originalImeSource != null && shouldImeAttachedToApp && (w.isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS) || !w.getRequestedVisibility(ITYPE_IME))) { final InsetsState state = copyState ? new InsetsState(originalState) : originalState; final InsetsSource imeSource = new InsetsSource(originalImeSource); imeSource.setVisible(false); state.addSource(imeSource); return state; } } return originalState; } Loading
services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +33 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL; import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowContainer.SYNC_STATE_WAITING_FOR_DRAW; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -891,6 +894,36 @@ public class WindowStateTests extends WindowTestsBase { assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)); } @UseTestDisplay(addWindows = W_INPUT_METHOD) @Test public void testAdjustImeInsetsVisibilityWhenTaskSwitchIsAnimating() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2"); final InsetsStateController controller = mDisplayContent.getInsetsStateController(); controller.getImeSourceProvider().setWindow(mImeWindow, null, null); // Simulate app requests IME with updating all windows Insets State when IME is above app. mDisplayContent.setImeLayeringTarget(app); mDisplayContent.setImeInputTarget(app); assertTrue(mDisplayContent.shouldImeAttachedToApp()); controller.getImeSourceProvider().scheduleShowImePostLayout(app); controller.getImeSourceProvider().getSource().setVisible(true); controller.updateAboveInsetsState(mImeWindow, false); // Simulate task switching animation happens when switching app to app2. spyOn(app); spyOn(app2); doReturn(true).when(app).isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS); doReturn(true).when(app2).isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS); app.mActivityRecord.mLastImeShown = true; // Verify the IME insets is visible on app, but not for app2 during task animating. InsetsState stateApp = app.getInsetsState(); InsetsState stateApp2 = app2.getInsetsState(); assertTrue(stateApp.getSource(ITYPE_IME).isVisible()); assertFalse(stateApp2.getSource(ITYPE_IME).isVisible()); } @UseTestDisplay(addWindows = { W_ACTIVITY }) @Test public void testUpdateImeControlTargetWhenLeavingMultiWindow() { Loading