diff options
| author | 2020-02-12 02:45:41 +0000 | |
|---|---|---|
| committer | 2020-02-12 02:45:41 +0000 | |
| commit | e8d7ecdbb1ba81cbdb83156201e26fae1e154986 (patch) | |
| tree | 139739e9b3462d6d4ad93e5b7ad1a5129b9755ad | |
| parent | 524ec05bc60ed2cb973376de09372783b7a416b6 (diff) | |
| parent | 3406fb97f4c5bc61727a1638b07af74aa8cca227 (diff) | |
Merge "Insets Animation: Add CancellationSignal to controlWindowInsetsAnimation"
| -rw-r--r-- | api/current.txt | 2 | ||||
| -rw-r--r-- | core/java/android/view/InsetsController.java | 50 | ||||
| -rw-r--r-- | core/java/android/view/WindowInsetsController.java | 7 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/InsetsControllerTest.java | 51 |
4 files changed, 92 insertions, 18 deletions
diff --git a/api/current.txt b/api/current.txt index 88f7f03e3a28..a12da182dcab 100644 --- a/api/current.txt +++ b/api/current.txt @@ -55209,7 +55209,7 @@ package android.view { } public interface WindowInsetsController { - method public void controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener); + method @NonNull public android.os.CancellationSignal controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener); method public int getSystemBarsAppearance(); method public int getSystemBarsBehavior(); method public void hide(int); diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 54de1bb3739d..15be364c3e1c 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -32,6 +32,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Insets; import android.graphics.Rect; +import android.os.CancellationSignal; import android.os.Handler; import android.os.RemoteException; import android.util.ArraySet; @@ -39,7 +40,6 @@ import android.util.Log; import android.util.Pair; import android.util.Property; import android.util.SparseArray; -import android.view.InputDevice.MotionRange; import android.view.InsetsSourceConsumer.ShowResult; import android.view.InsetsState.InternalInsetsType; import android.view.SurfaceControl.Transaction; @@ -242,13 +242,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation PendingControlRequest(@InsetsType int types, WindowInsetsAnimationControlListener listener, long durationMs, Interpolator interpolator, @AnimationType int animationType, - @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) { + @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation, + CancellationSignal cancellationSignal) { this.types = types; this.listener = listener; this.durationMs = durationMs; this.interpolator = interpolator; this.animationType = animationType; this.layoutInsetsDuringAnimation = layoutInsetsDuringAnimation; + this.cancellationSignal = cancellationSignal; } final @InsetsType int types; @@ -257,6 +259,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation final Interpolator interpolator; final @AnimationType int animationType; final @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation; + final CancellationSignal cancellationSignal; } private final String TAG = "InsetsControllerImpl"; @@ -455,10 +458,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation PendingControlRequest pendingRequest = mPendingImeControlRequest; mPendingImeControlRequest = null; mHandler.removeCallbacks(mPendingControlTimeout); - controlAnimationUnchecked(pendingRequest.types, pendingRequest.listener, mFrame, + CancellationSignal cancellationSignal = controlAnimationUnchecked( + pendingRequest.types, + pendingRequest.listener, mFrame, true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator, false /* fade */, pendingRequest.animationType, pendingRequest.layoutInsetsDuringAnimation); + pendingRequest.cancellationSignal.setOnCancelListener(cancellationSignal::cancel); return; } @@ -504,35 +510,39 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } @Override - public void controlWindowInsetsAnimation(@InsetsType int types, long durationMs, + public CancellationSignal controlWindowInsetsAnimation(@InsetsType int types, long durationMs, @Nullable Interpolator interpolator, @NonNull WindowInsetsAnimationControlListener listener) { - controlWindowInsetsAnimation(types, listener, false /* fromIme */, durationMs, interpolator, - ANIMATION_TYPE_USER); + return controlWindowInsetsAnimation(types, listener, false /* fromIme */, durationMs, + interpolator, ANIMATION_TYPE_USER); } - private void controlWindowInsetsAnimation(@InsetsType int types, + private CancellationSignal controlWindowInsetsAnimation(@InsetsType int types, WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs, @Nullable Interpolator interpolator, @AnimationType int animationType) { // If the frame of our window doesn't span the entire display, the control API makes very // little sense, as we don't deal with negative insets. So just cancel immediately. if (!mState.getDisplayFrame().equals(mFrame)) { listener.onCancelled(); - return; + CancellationSignal cancellationSignal = new CancellationSignal(); + cancellationSignal.cancel(); + return cancellationSignal; } - controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, interpolator, + return controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, interpolator, false /* fade */, animationType, getLayoutInsetsDuringAnimationMode(types)); } - private void controlAnimationUnchecked(@InsetsType int types, + private CancellationSignal controlAnimationUnchecked(@InsetsType int types, WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme, long durationMs, Interpolator interpolator, boolean fade, @AnimationType int animationType, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) { + CancellationSignal cancellationSignal = new CancellationSignal(); if (types == 0) { // nothing to animate. listener.onCancelled(); - return; + cancellationSignal.cancel(); + return cancellationSignal; } cancelExistingControllers(types); @@ -546,21 +556,31 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (!imeReady) { // IME isn't ready, all requested types will be animated once IME is ready abortPendingImeControlRequest(); - mPendingImeControlRequest = new PendingControlRequest(types, listener, durationMs, - interpolator, animationType, layoutInsetsDuringAnimation); + final PendingControlRequest request = new PendingControlRequest(types, + listener, durationMs, + interpolator, animationType, layoutInsetsDuringAnimation, cancellationSignal); + mPendingImeControlRequest = request; mHandler.postDelayed(mPendingControlTimeout, PENDING_CONTROL_TIMEOUT_MS); - return; + cancellationSignal.setOnCancelListener(() -> { + if (mPendingImeControlRequest == request) { + abortPendingImeControlRequest(); + } + }); + return cancellationSignal; } if (typesReady == 0) { listener.onCancelled(); - return; + cancellationSignal.cancel(); + return cancellationSignal; } final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(controls, frame, mState, listener, typesReady, this, durationMs, interpolator, fade, layoutInsetsDuringAnimation); mRunningAnimations.add(new RunningAnimation(controller, animationType)); + cancellationSignal.setOnCancelListener(controller::onCancelled); + return cancellationSignal; } /** diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java index ea8e73885980..27e92e559b09 100644 --- a/core/java/android/view/WindowInsetsController.java +++ b/core/java/android/view/WindowInsetsController.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Insets; +import android.os.CancellationSignal; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowInsetsAnimationCallback.InsetsAnimation; import android.view.animation.Interpolator; @@ -154,13 +155,15 @@ public interface WindowInsetsController { * {@link InsetsAnimation#getInterpolatedFraction()}. * @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the * windows are ready to be controlled, among other callbacks. - * + * @return A cancellation signal that the caller can use to cancel the request to obtain + * control, or once they have control, to cancel the control. * @see InsetsAnimation#getFraction() * @see InsetsAnimation#getInterpolatedFraction() * @see InsetsAnimation#getInterpolator() * @see InsetsAnimation#getDurationMillis() */ - void controlWindowInsetsAnimation(@InsetsType int types, long durationMillis, + @NonNull + CancellationSignal controlWindowInsetsAnimation(@InsetsType int types, long durationMillis, @Nullable Interpolator interpolator, @NonNull WindowInsetsAnimationControlListener listener); diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index 2c9dba1d59fd..24fe2a0a1823 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -45,6 +45,7 @@ import android.content.Context; import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; +import android.os.CancellationSignal; import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type; @@ -516,6 +517,34 @@ public class InsetsControllerTest { } @Test + public void testCancellation_afterGainingControl() throws Exception { + InsetsSourceControl control = + new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()); + mController.onControlsChanged(new InsetsSourceControl[] { control }); + + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + WindowInsetsAnimationControlListener mockListener = + mock(WindowInsetsAnimationControlListener.class); + CancellationSignal cancellationSignal = mController.controlWindowInsetsAnimation( + statusBars(), 0 /* durationMs */, + new LinearInterpolator(), mockListener); + + // Ready gets deferred until next predraw + mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw(); + + verify(mockListener).onReady(any(), anyInt()); + + cancellationSignal.cancel(); + verify(mockListener).onCancelled(); + }); + waitUntilNextFrame(); + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible()); + }); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + } + + @Test public void testControlImeNotReady() { prepareControls(); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { @@ -580,6 +609,28 @@ public class InsetsControllerTest { }); } + @Test + public void testControlImeNotReady_cancel() { + prepareControls(); + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + WindowInsetsAnimationControlListener listener = + mock(WindowInsetsAnimationControlListener.class); + mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(), listener) + .cancel(); + + verify(listener).onCancelled(); + + // Ready gets deferred until next predraw + mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw(); + + verify(listener, never()).onReady(any(), anyInt()); + + // Pretend that timeout is happening + mTestClock.fastForward(2500); + mTestHandler.timeAdvance(); + }); + } + private void waitUntilNextFrame() throws Exception { final CountDownLatch latch = new CountDownLatch(1); Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT, |