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
diff --git a/api/current.txt b/api/current.txt
index 826bbbc..4b79621 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -55574,7 +55574,8 @@
}
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 @@
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 baee412..d2e6036 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -200,6 +200,7 @@
}
setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */);
mFinished = true;
+ mListener.onFinished(this);
mShownOnFinish = shown;
}
@@ -216,11 +217,17 @@
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 123b9db..96f7340 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -213,7 +213,11 @@
}
@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 @@
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 @@
boolean useInsetsAnimationThread) {
if (types == 0) {
// nothing to animate.
- listener.onCancelled();
+ listener.onCancelled(null);
return;
}
cancelExistingControllers(types);
@@ -641,7 +645,7 @@
}
if (typesReady == 0) {
- listener.onCancelled();
+ listener.onCancelled(null);
return;
}
@@ -756,7 +760,7 @@
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 e8d9bb5..229ee03 100644
--- a/core/java/android/view/PendingInsetsController.java
+++ b/core/java/android/view/PendingInsetsController.java
@@ -172,7 +172,7 @@
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 faaf920..b61fa36 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 @@
* {@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 onCancelled();
+ 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(@Nullable WindowInsetsAnimationController controller);
}
diff --git a/core/java/android/view/WindowInsetsAnimationController.java b/core/java/android/view/WindowInsetsAnimationController.java
index 2c7880b..c191a54 100644
--- a/core/java/android/view/WindowInsetsAnimationController.java
+++ b/core/java/android/view/WindowInsetsAnimationController.java
@@ -139,10 +139,43 @@
@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 fe25e79..22b4e45 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -188,7 +188,7 @@
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 42ab2e7..90a62e7 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -204,7 +204,7 @@
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 @@
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 @@
verify(mockListener).onReady(any(), anyInt());
cancellationSignal.cancel();
- verify(mockListener).onCancelled();
+ verify(mockListener).onCancelled(notNull());
});
waitUntilNextFrame();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
@@ -584,7 +584,7 @@
// Pretend that we are losing control
mController.onControlsChanged(new InsetsSourceControl[0]);
- verify(listener).onCancelled();
+ verify(listener).onCancelled(null);
});
}
@@ -606,7 +606,7 @@
mTestClock.fastForward(2500);
mTestHandler.timeAdvance();
- verify(listener).onCancelled();
+ verify(listener).onCancelled(null);
});
}
@@ -621,7 +621,7 @@
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 33f859e..03c8b1b 100644
--- a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
@@ -99,7 +99,7 @@
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 f254e4d..548af0c 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 @@
}
@Override
- public void onCancelled() {
+ public void onFinished(
+ WindowInsetsAnimationController controller) {
+ mAnimationController = null;
+ }
+
+ @Override
+ public void onCancelled(
+ WindowInsetsAnimationController controller) {
mAnimationController = null;
}
});
@@ -230,7 +237,13 @@
}
@Override
- public void onCancelled() {
+ public void onFinished(
+ WindowInsetsAnimationController controller) {
+ }
+
+ @Override
+ public void onCancelled(
+ WindowInsetsAnimationController controller) {
}
});
}