diff options
| author | 2021-05-10 18:36:27 +0800 | |
|---|---|---|
| committer | 2021-05-17 11:10:26 +0800 | |
| commit | a39967f4bcf6a8f413c429403a4f4294190455da (patch) | |
| tree | 48a909f680841c86f52e80dd9a30388203a79491 | |
| parent | 3ee3029e96912b267fb11e357fd9551631ceda2c (diff) | |
Force showing navigation bar while IME is visible
This CL revokes navigation bar control to make navigation bar visible
while IME is showing, so the button to dismiss IME would be available.
This CL also lets IME receive visible navigation bar insets, regardless
of the navigation bar visibility.
Fix: 167971834
Fix: 186789472
Test: atest WindowStateTests WindowInsetsControllerTests
Change-Id: I2e723d4fc50d006127caa473d67c2f6af0d2cbcd
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() { |