diff options
author | 2020-03-17 20:04:35 +0100 | |
---|---|---|
committer | 2020-03-18 12:17:19 +0100 | |
commit | 5d557edb448ae807072c1dde625a972e1ddf0b2a (patch) | |
tree | fcc80875d4450e20f2afdf7d63ca4399d15dbf6d | |
parent | e88d949e0a191e2419eb207ac3a9a852fa012686 (diff) |
WindowInsetsAnimationController: Add state callback and getters
Adds more comprehensive callbacks and getters for the WindowInsetsAnimationController,
to make it more straight forward to properly use.
Test: atest InsetsControllerTest PendingInsetsControllerTest
Fixes: 151707442
Change-Id: Ida55f609112396c0f6de4c5c4431e0793c2e315e
10 files changed, 129 insertions, 32 deletions
diff --git a/api/current.txt b/api/current.txt index 826bbbc6e692..4b796213f35e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -55574,7 +55574,8 @@ package android.view { } public interface WindowInsetsAnimationControlListener { - method public void onCancelled(); + method public void onCancelled(@Nullable android.view.WindowInsetsAnimationController); + method public void onFinished(@NonNull android.view.WindowInsetsAnimationController); method public void onReady(@NonNull android.view.WindowInsetsAnimationController, int); } @@ -55586,6 +55587,9 @@ package android.view { method @NonNull public android.graphics.Insets getHiddenStateInsets(); method @NonNull public android.graphics.Insets getShownStateInsets(); method public int getTypes(); + method public boolean isCancelled(); + method public boolean isFinished(); + method public default boolean isReady(); method public void setInsetsAndAlpha(@Nullable android.graphics.Insets, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float); } diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index baee4123ef47..d2e603649655 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -200,6 +200,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll } setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */); mFinished = true; + mListener.onFinished(this); mShownOnFinish = shown; } @@ -216,11 +217,17 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll return; } mCancelled = true; - mListener.onCancelled(); + mListener.onCancelled(this); releaseLeashes(); } + @Override + public boolean isFinished() { + return mFinished; + } + + @Override public boolean isCancelled() { return mCancelled; } diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 123b9db75804..96f73409ae0b 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -213,7 +213,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } @Override - public void onCancelled() { + public void onFinished(WindowInsetsAnimationController controller) { + } + + @Override + public void onCancelled(WindowInsetsAnimationController controller) { // Animator can be null when it is cancelled before onReady() completes. if (mAnimator != null) { mAnimator.cancel(); @@ -583,7 +587,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation boolean fromIme, long durationMs, @Nullable Interpolator interpolator, @AnimationType int animationType) { if (!checkDisplayFramesForControlling()) { - listener.onCancelled(); + listener.onCancelled(null); return; } controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs, @@ -608,7 +612,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation boolean useInsetsAnimationThread) { if (types == 0) { // nothing to animate. - listener.onCancelled(); + listener.onCancelled(null); return; } cancelExistingControllers(types); @@ -641,7 +645,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } if (typesReady == 0) { - listener.onCancelled(); + listener.onCancelled(null); return; } @@ -756,7 +760,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private void abortPendingImeControlRequest() { if (mPendingImeControlRequest != null) { - mPendingImeControlRequest.listener.onCancelled(); + mPendingImeControlRequest.listener.onCancelled(null); mPendingImeControlRequest = null; mHandler.removeCallbacks(mPendingControlTimeout); } diff --git a/core/java/android/view/PendingInsetsController.java b/core/java/android/view/PendingInsetsController.java index e8d9bb50c290..229ee03521bc 100644 --- a/core/java/android/view/PendingInsetsController.java +++ b/core/java/android/view/PendingInsetsController.java @@ -172,7 +172,7 @@ public class PendingInsetsController implements WindowInsetsController { mReplayedInsetsController.controlWindowInsetsAnimation(types, durationMillis, interpolator, cancellationSignal, listener); } else { - listener.onCancelled(); + listener.onCancelled(null); } } diff --git a/core/java/android/view/WindowInsetsAnimationControlListener.java b/core/java/android/view/WindowInsetsAnimationControlListener.java index faaf9203af32..b61fa36f0e2a 100644 --- a/core/java/android/view/WindowInsetsAnimationControlListener.java +++ b/core/java/android/view/WindowInsetsAnimationControlListener.java @@ -17,21 +17,31 @@ package android.view; import android.annotation.NonNull; +import android.annotation.Nullable; import android.view.WindowInsets.Type.InsetsType; import android.view.inputmethod.EditorInfo; /** - * Interface that informs the client about {@link WindowInsetsAnimationController} state changes. + * Listener that encapsulates a request to + * {@link WindowInsetsController#controlWindowInsetsAnimation}. + * + * <p> + * Insets can be controlled with the supplied {@link WindowInsetsAnimationController} from + * {@link #onReady} until either {@link #onFinished} or {@link #onCancelled}. + * + * <p> + * Once the control over insets is finished or cancelled, it will not be regained until a new + * request to {@link WindowInsetsController#controlWindowInsetsAnimation} is made. + * + * <p> + * The request to control insets can fail immediately. In that case {@link #onCancelled} will be + * invoked without a preceding {@link #onReady}. + * + * @see WindowInsetsController#controlWindowInsetsAnimation */ public interface WindowInsetsAnimationControlListener { /** - * @hide - */ - default void onPrepare(int types) { - } - - /** * Called when the animation is ready to be controlled. This may be delayed when the IME needs * to redraw because of an {@link EditorInfo} change, or when the window is starting up. * @@ -41,14 +51,40 @@ public interface WindowInsetsAnimationControlListener { * {@link WindowInsetsController#controlWindowInsetsAnimation} in case the window * wasn't able to gain the controls because it wasn't the IME target or not * currently the window that's controlling the system bars. + * @see WindowInsetsAnimationController#isReady */ void onReady(@NonNull WindowInsetsAnimationController controller, @InsetsType int types); /** - * Called when the window no longer has control over the requested types. If it loses control - * over one type, the whole control will be cancelled. If none of the requested types were - * available when requesting the control, the animation control will be cancelled immediately - * without {@link #onReady} being called. + * Called when the request for control over the insets has + * {@link WindowInsetsAnimationController#finish finished}. + * + * Once this callback is invoked, the supplied {@link WindowInsetsAnimationController} + * is no longer {@link WindowInsetsAnimationController#isReady() ready}. + * + * Control will not be regained until a new request + * to {@link WindowInsetsController#controlWindowInsetsAnimation} is made. + * + * @param controller the controller which has finished. + * @see WindowInsetsAnimationController#isFinished + */ + void onFinished(@NonNull WindowInsetsAnimationController controller); + + /** + * Called when the request for control over the insets has been cancelled, either + * because the {@link android.os.CancellationSignal} associated with the + * {@link WindowInsetsController#controlWindowInsetsAnimation request} has been invoked, or + * the window has lost control over the insets (e.g. because it lost focus). + * + * Once this callback is invoked, the supplied {@link WindowInsetsAnimationController} + * is no longer {@link WindowInsetsAnimationController#isReady() ready}. + * + * Control will not be regained until a new request + * to {@link WindowInsetsController#controlWindowInsetsAnimation} is made. + * + * @param controller the controller which has been cancelled, or null if the request + * was cancelled before {@link #onReady} was invoked. + * @see WindowInsetsAnimationController#isCancelled */ - void onCancelled(); + void onCancelled(@Nullable WindowInsetsAnimationController controller); } diff --git a/core/java/android/view/WindowInsetsAnimationController.java b/core/java/android/view/WindowInsetsAnimationController.java index 2c7880b09785..c191a54283fb 100644 --- a/core/java/android/view/WindowInsetsAnimationController.java +++ b/core/java/android/view/WindowInsetsAnimationController.java @@ -139,10 +139,43 @@ public interface WindowInsetsAnimationController { @FloatRange(from = 0f, to = 1f) float fraction); /** - * Finishes the animation, and leaves the windows shown or hidden. After invoking - * {@link #finish(boolean)}, this instance is no longer valid. + * Finishes the animation, and leaves the windows shown or hidden. + * <p> + * After invoking {@link #finish(boolean)}, this instance is no longer {@link #isReady ready}. + * * @param shown if {@code true}, the windows will be shown after finishing the * animation. Otherwise they will be hidden. */ void finish(boolean shown); + + /** + * Returns whether this instance is ready to be used to control window insets. + * <p> + * Instances are ready when passed in {@link WindowInsetsAnimationControlListener#onReady} + * and stop being ready when it is either {@link #isFinished() finished} or + * {@link #isCancelled() cancelled}. + * + * @return {@code true} if the instance is ready, {@code false} otherwise. + */ + default boolean isReady() { + return !isFinished() && !isCancelled(); + } + + /** + * Returns whether this instance has been finished by a call to {@link #finish}. + * + * @see WindowInsetsAnimationControlListener#onFinished + * @return {@code true} if the instance is finished, {@code false} otherwise. + */ + boolean isFinished(); + + /** + * Returns whether this instance has been cancelled by the system, or by invoking the + * {@link android.os.CancellationSignal} passed into + * {@link WindowInsetsController#controlWindowInsetsAnimation}. + * + * @see WindowInsetsAnimationControlListener#onCancelled + * @return {@code true} if the instance is cancelled, {@code false} otherwise. + */ + boolean isCancelled(); } diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java index fe25e79df44e..22b4e45f068a 100644 --- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java +++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java @@ -188,7 +188,7 @@ public class InsetsAnimationControlImplTest { fail("Expected exception to be thrown"); } catch (IllegalStateException ignored) { } - verify(mMockListener).onCancelled(); + verify(mMockListener).onCancelled(mController); mController.finish(true /* shown */); } diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index 42ab2e791641..90a62e7a8751 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -204,7 +204,7 @@ public class InsetsControllerTest { mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw(); verify(mockListener).onReady(any(), anyInt()); mController.onControlsChanged(new InsetsSourceControl[0]); - verify(mockListener).onCancelled(); + verify(mockListener).onCancelled(notNull()); }); } @@ -221,7 +221,7 @@ public class InsetsControllerTest { new CancellationSignal(), controlListener); mController.addOnControllableInsetsChangedListener( (controller, typeMask) -> assertEquals(0, typeMask)); - verify(controlListener).onCancelled(); + verify(controlListener).onCancelled(null); verify(controlListener, never()).onReady(any(), anyInt()); } @@ -533,7 +533,7 @@ public class InsetsControllerTest { verify(mockListener).onReady(any(), anyInt()); cancellationSignal.cancel(); - verify(mockListener).onCancelled(); + verify(mockListener).onCancelled(notNull()); }); waitUntilNextFrame(); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { @@ -584,7 +584,7 @@ public class InsetsControllerTest { // Pretend that we are losing control mController.onControlsChanged(new InsetsSourceControl[0]); - verify(listener).onCancelled(); + verify(listener).onCancelled(null); }); } @@ -606,7 +606,7 @@ public class InsetsControllerTest { mTestClock.fastForward(2500); mTestHandler.timeAdvance(); - verify(listener).onCancelled(); + verify(listener).onCancelled(null); }); } @@ -621,7 +621,7 @@ public class InsetsControllerTest { cancellationSignal, listener); cancellationSignal.cancel(); - verify(listener).onCancelled(); + verify(listener).onCancelled(null); // Ready gets deferred until next predraw mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw(); diff --git a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java index 33f859ef6663..03c8b1bcb475 100644 --- a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java @@ -99,7 +99,7 @@ public class PendingInsetsControllerTest { CancellationSignal cancellationSignal = new CancellationSignal(); mPendingInsetsController.controlWindowInsetsAnimation( systemBars(), 0, new LinearInterpolator(), cancellationSignal, listener); - verify(listener).onCancelled(); + verify(listener).onCancelled(null); assertFalse(cancellationSignal.isCanceled()); } diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java index f254e4d3267a..548af0c54b03 100644 --- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java +++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java @@ -114,7 +114,14 @@ public class WindowInsetsActivity extends AppCompatActivity { } @Override - public void onCancelled() { + public void onFinished( + WindowInsetsAnimationController controller) { + mAnimationController = null; + } + + @Override + public void onCancelled( + WindowInsetsAnimationController controller) { mAnimationController = null; } }); @@ -230,7 +237,13 @@ public class WindowInsetsActivity extends AppCompatActivity { } @Override - public void onCancelled() { + public void onFinished( + WindowInsetsAnimationController controller) { + } + + @Override + public void onCancelled( + WindowInsetsAnimationController controller) { } }); } |