diff options
6 files changed, 89 insertions, 4 deletions
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index a2cb1d5c6bd2..0e3bcd1b6842 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -314,6 +314,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation (int) (startValue.right + fraction * (endValue.right - startValue.right)), (int) (startValue.bottom + fraction * (endValue.bottom - startValue.bottom))); + /** Logging listener. */ + private WindowInsetsAnimationControlListener mLoggingListener; + /** * The default implementation of listener, to be used by InsetsController and InsetsPolicy to * animate insets. @@ -330,6 +333,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final long mDurationMs; private final boolean mDisable; private final int mFloatingImeBottomInset; + private final WindowInsetsAnimationControlListener mLoggingListener; private final ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal = new ThreadLocal<AnimationHandler>() { @@ -343,7 +347,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation public InternalAnimationControlListener(boolean show, boolean hasAnimationCallbacks, @InsetsType int requestedTypes, @Behavior int behavior, boolean disable, - int floatingImeBottomInset) { + int floatingImeBottomInset, WindowInsetsAnimationControlListener loggingListener) { mShow = show; mHasAnimationCallbacks = hasAnimationCallbacks; mRequestedTypes = requestedTypes; @@ -351,12 +355,16 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mDurationMs = calculateDurationMs(); mDisable = disable; mFloatingImeBottomInset = floatingImeBottomInset; + mLoggingListener = loggingListener; } @Override public void onReady(WindowInsetsAnimationController controller, int types) { mController = controller; if (DEBUG) Log.d(TAG, "default animation onReady types: " + types); + if (mLoggingListener != null) { + mLoggingListener.onReady(controller, types); + } if (mDisable) { onAnimationFinish(); @@ -410,6 +418,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation public void onFinished(WindowInsetsAnimationController controller) { if (DEBUG) Log.d(TAG, "InternalAnimationControlListener onFinished types:" + Type.toString(mRequestedTypes)); + if (mLoggingListener != null) { + mLoggingListener.onFinished(controller); + } } @Override @@ -420,6 +431,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } if (DEBUG) Log.d(TAG, "InternalAnimationControlListener onCancelled types:" + mRequestedTypes); + if (mLoggingListener != null) { + mLoggingListener.onCancelled(controller); + } } protected Interpolator getInsetsInterpolator() { @@ -1147,6 +1161,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation updateRequestedVisibilities(); } + // TODO(b/242962223): Make this setter restrictive. + @Override + public void setSystemDrivenInsetsAnimationLoggingListener( + @Nullable WindowInsetsAnimationControlListener listener) { + mLoggingListener = listener; + } + /** * @return Pair of (types ready to animate, IME ready to animate). */ @@ -1460,7 +1481,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks(); final InternalAnimationControlListener listener = new InternalAnimationControlListener( show, hasAnimationCallbacks, types, mHost.getSystemBarsBehavior(), - skipAnim || mAnimationsDisabled, mHost.dipToPx(FLOATING_IME_BOTTOM_INSET_DP)); + skipAnim || mAnimationsDisabled, mHost.dipToPx(FLOATING_IME_BOTTOM_INSET_DP), + mLoggingListener); // We are about to playing the default animation (show/hide). Passing a null frame indicates // the controlled types should be animated regardless of the frame. diff --git a/core/java/android/view/PendingInsetsController.java b/core/java/android/view/PendingInsetsController.java index c61baf6fb40c..3fe9110283a6 100644 --- a/core/java/android/view/PendingInsetsController.java +++ b/core/java/android/view/PendingInsetsController.java @@ -44,6 +44,7 @@ public class PendingInsetsController implements WindowInsetsController { private ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners = new ArrayList<>(); private int mCaptionInsetsHeight = 0; + private WindowInsetsAnimationControlListener mLoggingListener; @Override public void show(int types) { @@ -176,6 +177,9 @@ public class PendingInsetsController implements WindowInsetsController { controller.addOnControllableInsetsChangedListener( mControllableInsetsChangedListeners.get(i)); } + if (mLoggingListener != null) { + controller.setSystemDrivenInsetsAnimationLoggingListener(mLoggingListener); + } // Reset all state so it doesn't get applied twice just in case mRequests.clear(); @@ -184,7 +188,7 @@ public class PendingInsetsController implements WindowInsetsController { mAppearance = 0; mAppearanceMask = 0; mAnimationsDisabled = false; - + mLoggingListener = null; // After replaying, we forward everything directly to the replayed instance. mReplayedInsetsController = controller; } @@ -198,6 +202,16 @@ public class PendingInsetsController implements WindowInsetsController { } @Override + public void setSystemDrivenInsetsAnimationLoggingListener( + @Nullable WindowInsetsAnimationControlListener listener) { + if (mReplayedInsetsController != null) { + mReplayedInsetsController.setSystemDrivenInsetsAnimationLoggingListener(listener); + } else { + mLoggingListener = listener; + } + } + + @Override public void controlWindowInsetsAnimation(@InsetsType int types, long durationMillis, @Nullable Interpolator interpolator, CancellationSignal cancellationSignal, diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java index 227b9f402bba..63f9e13214ff 100644 --- a/core/java/android/view/WindowInsetsController.java +++ b/core/java/android/view/WindowInsetsController.java @@ -201,6 +201,21 @@ public interface WindowInsetsController { @NonNull WindowInsetsAnimationControlListener listener); /** + * Lets the application add non-controllable listener object that can be called back + * when animation is invoked by the system by host calling methods such as {@link #show} or + * {@link #hide}. + * + * The listener is supposed to be used for logging only, using the control or + * relying on the timing of the callback in any other way is not supported. + * + * @param listener The {@link WindowInsetsAnimationControlListener} that gets called when + * the animation is driven by the system and not the host + * @hide + */ + void setSystemDrivenInsetsAnimationLoggingListener( + @Nullable WindowInsetsAnimationControlListener listener); + + /** * Controls the appearance of system bars. * <p> * For example, the following statement adds {@link #APPEARANCE_LIGHT_STATUS_BARS}: diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index ed6a649021a1..6e59b83810e1 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -236,6 +236,21 @@ public class InsetsControllerTest { } @Test + public void testSystemDrivenInsetsAnimationLoggingListener_onReady() { + prepareControls(); + // only the original thread that created view hierarchy can touch its views + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + WindowInsetsAnimationControlListener loggingListener = + mock(WindowInsetsAnimationControlListener.class); + mController.setSystemDrivenInsetsAnimationLoggingListener(loggingListener); + mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained(true); + // since there is no focused view, forcefully make IME visible. + mController.show(Type.ime(), true /* fromIme */); + verify(loggingListener).onReady(notNull(), anyInt()); + }); + } + + @Test public void testAnimationEndState() { InsetsSourceControl[] controls = prepareControls(); InsetsSourceControl navBar = controls[0]; diff --git a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java index 03c8b1bcb475..690b35879388 100644 --- a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java @@ -213,6 +213,25 @@ public class PendingInsetsControllerTest { } @Test + public void testSystemDrivenInsetsAnimationLoggingListener() { + WindowInsetsAnimationControlListener listener = + mock(WindowInsetsAnimationControlListener.class); + mPendingInsetsController.setSystemDrivenInsetsAnimationLoggingListener(listener); + mPendingInsetsController.replayAndAttach(mReplayedController); + verify(mReplayedController).setSystemDrivenInsetsAnimationLoggingListener(eq(listener)); + } + + @Test + public void testSystemDrivenInsetsAnimationLoggingListener_direct() { + mPendingInsetsController.replayAndAttach(mReplayedController); + WindowInsetsAnimationControlListener listener = + mock(WindowInsetsAnimationControlListener.class); + mPendingInsetsController.setSystemDrivenInsetsAnimationLoggingListener(listener); + verify(mReplayedController).setSystemDrivenInsetsAnimationLoggingListener( + eq(listener)); + } + + @Test public void testDetachReattach() { mPendingInsetsController.show(systemBars()); mPendingInsetsController.setSystemBarsBehavior(BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index 7a9e6a977dfa..f3bd1a15cc94 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -761,7 +761,7 @@ class InsetsPolicy { InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) { super(show, false /* hasCallbacks */, types, BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE, - false /* disable */, 0 /* floatingImeBottomInsets */); + false /* disable */, 0 /* floatingImeBottomInsets */, null); mFinishCallback = finishCallback; mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this); } |