diff options
3 files changed, 102 insertions, 1 deletions
diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java index 0519b80c732a..529c4f608743 100644 --- a/services/core/java/com/android/server/wm/AnimationAdapter.java +++ b/services/core/java/com/android/server/wm/AnimationAdapter.java @@ -85,4 +85,25 @@ interface AnimationAdapter { } void dumpDebug(ProtoOutputStream proto); + + /** + * Gets called when the animation is about to finish and gives the client the opportunity to + * defer finishing the animation, i.e. it keeps the leash around until the client calls + * endDeferFinishCallback. + * <p> + * This has the same effect as + * {@link com.android.server.wm.SurfaceAnimator.Animatable#shouldDeferAnimationFinish(Runnable)} + * . The later will be evaluated first and has precedence over this method if it returns true, + * which means that if the {@link com.android.server.wm.SurfaceAnimator.Animatable} requests to + * defer its finish, this method won't be called so this adapter will never have access to the + * finish callback. On the other hand, if the + * {@link com.android.server.wm.SurfaceAnimator.Animatable}, doesn't request to defer, this + * {@link AnimationAdapter} is responsible for ending the animation. + * + * @param endDeferFinishCallback The callback to call when defer finishing should be ended. + * @return Whether the client would like to defer the animation finish. + */ + default boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { + return false; + } } diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 18e32c0683d6..42342a60ba16 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -109,7 +109,10 @@ class SurfaceAnimator { animationFinishCallback.onAnimationFinished(type, anim); } }; - if (!mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)) { + // If both the Animatable and AnimationAdapter requests to be deferred, only the + // first one will be called. + if (!(mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish) + || anim.shouldDeferAnimationFinish(resetAndInvokeFinish))) { resetAndInvokeFinish.run(); } } @@ -592,6 +595,12 @@ class SurfaceAnimator { * Gets called when the animation is about to finish and gives the client the opportunity to * defer finishing the animation, i.e. it keeps the leash around until the client calls * {@link #cancelAnimation}. + * <p> + * {@link AnimationAdapter} has a similar method which is called only if this method returns + * false. This mean that if both this {@link Animatable} and the {@link AnimationAdapter} + * request to be deferred, this method is the sole responsible to call + * endDeferFinishCallback. On the other hand, the animation finish might still be deferred + * if this method return false and the one from the {@link AnimationAdapter} returns true. * * @param endDeferFinishCallback The callback to call when defer finishing should be ended. * @return Whether the client would like to defer the animation finish. diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java index 552c476613b2..79ba1759f4c4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java @@ -33,6 +33,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import android.platform.test.annotations.Presubmit; +import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; import android.view.SurfaceControl.Builder; import android.view.SurfaceControl.Transaction; @@ -52,6 +53,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.io.PrintWriter; + /** * Test class for {@link SurfaceAnimatorTest}. * @@ -267,6 +270,27 @@ public class SurfaceAnimatorTest extends WindowTestsBase { assertFalse(mDeferFinishAnimatable.mFinishedCallbackCalled); } + @Test + public void testDeferFinishFromAdapter() { + + DeferredFinishAdapter deferredFinishAdapter = new DeferredFinishAdapter(); + // Start animation + mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, deferredFinishAdapter, + true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); + assertAnimating(mAnimatable); + deferredFinishAdapter.mFinishCallback.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, + deferredFinishAdapter); + + assertAnimating(mAnimatable); + assertFalse(mAnimatable.mFinishedCallbackCalled); + // Now end defer finishing. + deferredFinishAdapter.mEndDeferFinishCallback.run(); + assertNotAnimating(mAnimatable); + assertTrue(mAnimatable.mFinishedCallbackCalled); + verify(mTransaction).remove(eq(deferredFinishAdapter.mAnimationLeash)); + } + private OnAnimationFinishedCallback startDeferFinishAnimatable(AnimationAdapter anim) { mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, anim, true /* hidden */, ANIMATION_TYPE_APP_TRANSITION); @@ -389,4 +413,51 @@ public class SurfaceAnimatorTest extends WindowTestsBase { return true; } } + + private static class DeferredFinishAdapter implements AnimationAdapter { + + private Runnable mEndDeferFinishCallback; + private OnAnimationFinishedCallback mFinishCallback; + private SurfaceControl mAnimationLeash; + + @Override + public boolean getShowWallpaper() { + return true; + } + + @Override + public void startAnimation(SurfaceControl animationLeash, Transaction t, int type, + OnAnimationFinishedCallback finishCallback) { + mFinishCallback = finishCallback; + mAnimationLeash = animationLeash; + } + + @Override + public void onAnimationCancelled(SurfaceControl animationLeash) { + } + + @Override + public long getDurationHint() { + return 100; + } + + @Override + public long getStatusBarTransitionsStartTime() { + return 100; + } + + @Override + public void dump(PrintWriter pw, String prefix) { + } + + @Override + public void dumpDebug(ProtoOutputStream proto) { + } + + @Override + public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { + mEndDeferFinishCallback = endDeferFinishCallback; + return true; + } + } } |