diff options
6 files changed, 86 insertions, 7 deletions
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index a67ec10e1bd7..3255dd65b193 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -86,6 +86,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll private final InsetsState mInitialInsetsState; private final @AnimationType int mAnimationType; private final @InsetsType int mTypes; + private @InsetsType int mControllingTypes; private final InsetsAnimationControlCallbacks mController; private final WindowInsetsAnimation mAnimation; /** @see WindowInsetsAnimationController#hasZeroInsetsIme */ @@ -112,6 +113,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll mControls = controls; mListener = listener; mTypes = types; + mControllingTypes = types; mController = controller; mInitialInsetsState = new InsetsState(state, true /* copySources */); if (frame != null) { @@ -187,6 +189,16 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll } @Override + public int getControllingTypes() { + return mControllingTypes; + } + + @Override + public void notifyControlRevoked(@InsetsType int types) { + mControllingTypes &= ~types; + } + + @Override public @AnimationType int getAnimationType() { return mAnimationType; } diff --git a/core/java/android/view/InsetsAnimationControlRunner.java b/core/java/android/view/InsetsAnimationControlRunner.java index 0275b521a2a2..7787af5e133b 100644 --- a/core/java/android/view/InsetsAnimationControlRunner.java +++ b/core/java/android/view/InsetsAnimationControlRunner.java @@ -29,11 +29,22 @@ import android.view.WindowInsets.Type.InsetsType; public interface InsetsAnimationControlRunner { /** - * @return The {@link InsetsType} the animation of this runner is controlling. + * @return The {@link InsetsType} the animation of this runner controls. */ @InsetsType int getTypes(); /** + * @return The {@link InsetsType} the animation of this runner is controlling. This can be + * changed if a control is revoked. + */ + @InsetsType int getControllingTypes(); + + /** + * Notifies {@link InsetsType types} of control are getting revoked. + */ + void notifyControlRevoked(@InsetsType int types); + + /** * Cancels the animation. */ void cancel(); diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java index 6122c90ce06e..436a17c0de0b 100644 --- a/core/java/android/view/InsetsAnimationThreadControlRunner.java +++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java @@ -141,6 +141,17 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro @Override @UiThread + public int getControllingTypes() { + return mControl.getControllingTypes(); + } + + @Override + public void notifyControlRevoked(@InsetsType int types) { + mControl.notifyControlRevoked(types); + } + + @Override + @UiThread public void cancel() { InsetsAnimationThread.getHandler().post(mControl::cancel); } diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index def9ca4e74fb..de7cc18531a9 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -1224,9 +1224,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } void notifyControlRevoked(InsetsSourceConsumer consumer) { + final @InsetsType int types = toPublicType(consumer.getType()); for (int i = mRunningAnimations.size() - 1; i >= 0; i--) { InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner; - if ((control.getTypes() & toPublicType(consumer.getType())) != 0) { + control.notifyControlRevoked(types); + if (control.getControllingTypes() == 0) { cancelAnimation(control, true /* invokeCallback */); } } diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index cda3fdaea537..c387d338a3b2 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.view.InsetsController.ANIMATION_TYPE_HIDE; import static android.view.InsetsController.ANIMATION_TYPE_SHOW; +import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.SyncRtSurfaceTransactionApplier.applyParams; @@ -207,7 +208,8 @@ class InsetsPolicy { */ InsetsState getInsetsForWindow(WindowState target) { final InsetsState originalState = mStateController.getInsetsForWindow(target); - return adjustVisibilityForTransientTypes(originalState); + final InsetsState state = adjustVisibilityForTransientTypes(originalState); + return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state; } /** @@ -237,6 +239,20 @@ class InsetsPolicy { return state; } + // Navigation bar insets is always visible to IME. + private static InsetsState adjustVisibilityForIme(InsetsState originalState, + boolean copyState) { + final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR); + if (originalNavSource != null && !originalNavSource.isVisible()) { + final InsetsState state = copyState ? new InsetsState(originalState) : originalState; + final InsetsSource navSource = new InsetsSource(originalNavSource); + navSource.setVisible(true); + state.addSource(navSource); + return state; + } + return originalState; + } + void onInsetsModified(InsetsControlTarget caller) { mStateController.onInsetsModified(caller); checkAbortTransient(caller); @@ -245,17 +261,21 @@ class InsetsPolicy { /** * Called when a control target modified the insets state. If the target set a insets source to - * visible while it is shown transiently, we need to abort the transient state. + * visible while it is shown transiently, we need to abort the transient state. While IME is + * requested visible, we also need to abort the transient state of navigation bar if it is shown + * transiently. * * @param caller who changed the insets state. */ private void checkAbortTransient(InsetsControlTarget caller) { if (mShowingTransientTypes.size() != 0) { - IntArray abortTypes = new IntArray(); + final IntArray abortTypes = new IntArray(); + final boolean imeRequestedVisible = caller.getRequestedVisibility(ITYPE_IME); for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) { final @InternalInsetsType int type = mShowingTransientTypes.get(i); - if (mStateController.isFakeTarget(type, caller) - && caller.getRequestedVisibility(type)) { + if ((mStateController.isFakeTarget(type, caller) + && caller.getRequestedVisibility(type)) + || (type == ITYPE_NAVIGATION_BAR && imeRequestedVisible)) { mShowingTransientTypes.remove(i); abortTypes.add(type); } @@ -330,6 +350,11 @@ class InsetsPolicy { private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin, boolean forceShowsSystemBarsForWindowingMode) { + final WindowState imeWin = mDisplayContent.mInputMethodWindow; + if (imeWin != null && imeWin.isVisible()) { + // Force showing navigation bar while IME is visible. + return null; + } if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) { return mDummyControlTarget; } 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 8d067beff44c..e3b0bb263830 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; @@ -78,6 +79,7 @@ import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.view.Gravity; import android.view.InputWindowHandle; +import android.view.InsetsSource; import android.view.InsetsState; import android.view.SurfaceControl; import android.view.WindowManager; @@ -880,6 +882,22 @@ public class WindowStateTests extends WindowTestsBase { verify(app).notifyInsetsChanged(); } + @UseTestDisplay(addWindows = { W_INPUT_METHOD, W_ACTIVITY }) + @Test + public void testImeAlwaysReceivesVisibleNavigationBarInsets() { + final InsetsSource navSource = new InsetsSource(ITYPE_NAVIGATION_BAR); + mImeWindow.mAboveInsetsState.addSource(navSource); + mAppWindow.mAboveInsetsState.addSource(navSource); + + navSource.setVisible(false); + assertTrue(mImeWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)); + assertFalse(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)); + + navSource.setVisible(true); + assertTrue(mImeWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)); + assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)); + } + @UseTestDisplay(addWindows = { W_ACTIVITY }) @Test public void testUpdateImeControlTargetWhenLeavingMultiWindow() { |