Loading core/java/android/view/InsetsController.java +4 −1 Original line number Diff line number Diff line Loading @@ -1307,7 +1307,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs, @Nullable Interpolator interpolator, @AnimationType int animationType, boolean fromPredictiveBack) { if ((mState.calculateUncontrollableInsetsFromFrame(mFrame) & types) != 0) { if ((mState.calculateUncontrollableInsetsFromFrame(mFrame) & types) != 0 || (fromPredictiveBack && ((mRequestedVisibleTypes & ime()) == 0))) { // abort if insets are uncontrollable or if control request is from predictive back but // there is already a hide anim in progress listener.onCancelled(null); return; } Loading core/tests/coretests/src/android/view/InsetsControllerTest.java +31 −0 Original line number Diff line number Diff line Loading @@ -1131,6 +1131,37 @@ public class InsetsControllerTest { }); } @Test public void testPredictiveBackControlRequestCancelledDuringImeHideAnim() { prepareControls(); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { // show ime as initial state if (!Flags.refactorInsetsController()) { mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty()); } else { mController.show(ime(), false /* fromIme */, ImeTracker.Token.empty()); } mController.cancelExistingAnimations(); // fast forward show animation mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw(); assertTrue(mController.getState().peekSource(ID_IME).isVisible()); // start IME hide animation mController.hide(ime(), true /* fromIme */, null /* statsToken */); assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ime())); // start control request (for predictive back animation) WindowInsetsAnimationControlListener listener = mock(WindowInsetsAnimationControlListener.class); mController.controlWindowInsetsAnimation(ime(), /*cancellationSignal*/ null, listener, /*fromIme*/ false, /*duration*/ -1, /*interpolator*/ null, ANIMATION_TYPE_USER, /*fromPredictiveBack*/ true); // verify that control request is cancelled and animation type remains HIDE verify(listener).onCancelled(any()); assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ime())); }); } private void waitUntilNextFrame() throws Exception { final CountDownLatch latch = new CountDownLatch(1); Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT, Loading Loading
core/java/android/view/InsetsController.java +4 −1 Original line number Diff line number Diff line Loading @@ -1307,7 +1307,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs, @Nullable Interpolator interpolator, @AnimationType int animationType, boolean fromPredictiveBack) { if ((mState.calculateUncontrollableInsetsFromFrame(mFrame) & types) != 0) { if ((mState.calculateUncontrollableInsetsFromFrame(mFrame) & types) != 0 || (fromPredictiveBack && ((mRequestedVisibleTypes & ime()) == 0))) { // abort if insets are uncontrollable or if control request is from predictive back but // there is already a hide anim in progress listener.onCancelled(null); return; } Loading
core/tests/coretests/src/android/view/InsetsControllerTest.java +31 −0 Original line number Diff line number Diff line Loading @@ -1131,6 +1131,37 @@ public class InsetsControllerTest { }); } @Test public void testPredictiveBackControlRequestCancelledDuringImeHideAnim() { prepareControls(); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { // show ime as initial state if (!Flags.refactorInsetsController()) { mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty()); } else { mController.show(ime(), false /* fromIme */, ImeTracker.Token.empty()); } mController.cancelExistingAnimations(); // fast forward show animation mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw(); assertTrue(mController.getState().peekSource(ID_IME).isVisible()); // start IME hide animation mController.hide(ime(), true /* fromIme */, null /* statsToken */); assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ime())); // start control request (for predictive back animation) WindowInsetsAnimationControlListener listener = mock(WindowInsetsAnimationControlListener.class); mController.controlWindowInsetsAnimation(ime(), /*cancellationSignal*/ null, listener, /*fromIme*/ false, /*duration*/ -1, /*interpolator*/ null, ANIMATION_TYPE_USER, /*fromPredictiveBack*/ true); // verify that control request is cancelled and animation type remains HIDE verify(listener).onCancelled(any()); assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ime())); }); } private void waitUntilNextFrame() throws Exception { final CountDownLatch latch = new CountDownLatch(1); Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT, Loading