From b6d7002f365d92010c1d55910d7a231c82820314 Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Fri, 27 Mar 2020 23:51:56 +0800 Subject: [PATCH] Add test APIs for makeCustomAnimation For CTS to verify activity custom transition duration with onAnimationStartedListener / onAnimationFinishedListener in ActivityOptions Bug: 150443017 Test: build, atest ActivityTransitionTests Change-Id: I603ab60a65343f3f336b311064ad55b01ead4929 --- api/test-current.txt | 9 ++++ core/java/android/app/ActivityOptions.java | 39 +++++++++++++++++- .../shared/system/ActivityOptionsCompat.java | 2 +- .../com/android/server/wm/ActivityRecord.java | 11 ++--- .../server/wm/ActivityTaskManagerService.java | 2 +- .../com/android/server/wm/AppTransition.java | 41 +++++++++++-------- 6 files changed, 77 insertions(+), 27 deletions(-) diff --git a/api/test-current.txt b/api/test-current.txt index 0ca8b2dfb0d0d..08f662c2c1ac8 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -107,6 +107,7 @@ package android.app { } public class ActivityOptions { + method @NonNull public static android.app.ActivityOptions makeCustomAnimation(@NonNull android.content.Context, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener); method public static void setExitTransitionTimeout(long); method public void setLaunchActivityType(int); method public void setLaunchTaskId(int); @@ -115,6 +116,14 @@ package android.app { method public void setTaskOverlay(boolean, boolean); } + public static interface ActivityOptions.OnAnimationFinishedListener { + method public void onAnimationFinished(); + } + + public static interface ActivityOptions.OnAnimationStartedListener { + method public void onAnimationStarted(); + } + public class ActivityTaskManager { method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void clearLaunchParamsForPackages(java.util.List); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public String listAllStacks(); diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 7fd0211215c52..9833536a510be 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.INVALID_DISPLAY; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.TestApi; @@ -369,7 +370,7 @@ public class ActivityOptions { */ public static ActivityOptions makeCustomAnimation(Context context, int enterResId, int exitResId) { - return makeCustomAnimation(context, enterResId, exitResId, null, null); + return makeCustomAnimation(context, enterResId, exitResId, null, null, null); } /** @@ -403,6 +404,38 @@ public class ActivityOptions { return opts; } + /** + * Create an ActivityOptions specifying a custom animation to run when + * the activity is displayed. + * + * @param context Who is defining this. This is the application that the + * animation resources will be loaded from. + * @param enterResId A resource ID of the animation resource to use for + * the incoming activity. Use 0 for no animation. + * @param exitResId A resource ID of the animation resource to use for + * the outgoing activity. Use 0 for no animation. + * @param handler If listener is non-null this must be a valid + * Handler on which to dispatch the callback; otherwise it should be null. + * @param startedListener Optional OnAnimationStartedListener to find out when the + * requested animation has started running. If for some reason the animation + * is not executed, the callback will happen immediately. + * @param finishedListener Optional OnAnimationFinishedListener when the animation + * has finished running. + * @return Returns a new ActivityOptions object that you can use to + * supply these options as the options Bundle when starting an activity. + * @hide + */ + @TestApi + public static @NonNull ActivityOptions makeCustomAnimation(@NonNull Context context, + int enterResId, int exitResId, @Nullable Handler handler, + @Nullable OnAnimationStartedListener startedListener, + @Nullable OnAnimationFinishedListener finishedListener) { + ActivityOptions opts = makeCustomAnimation(context, enterResId, exitResId, handler, + startedListener); + opts.setOnAnimationFinishedListener(handler, finishedListener); + return opts; + } + /** * Creates an ActivityOptions specifying a custom animation to run in place on an existing * activity. @@ -448,6 +481,7 @@ public class ActivityOptions { * to find out when the given animation has started running. * @hide */ + @TestApi public interface OnAnimationStartedListener { void onAnimationStarted(); } @@ -474,6 +508,7 @@ public class ActivityOptions { * to find out when the given animation has drawn its last frame. * @hide */ + @TestApi public interface OnAnimationFinishedListener { void onAnimationFinished(); } @@ -1089,7 +1124,7 @@ public class ActivityOptions { } /** @hide */ - public IRemoteCallback getOnAnimationStartListener() { + public IRemoteCallback getAnimationStartedListener() { return mAnimationStartedListener; } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java index 7b39ba3d27596..345a649a036fb 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java @@ -76,7 +76,7 @@ public abstract class ActivityOptionsCompat { callbackHandler.post(callback); } } - }); + }, null /* finishedListener */); } /** diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index c1c844078d6fb..e33871503d105 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3739,7 +3739,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pendingOptions.getPackageName(), pendingOptions.getCustomEnterResId(), pendingOptions.getCustomExitResId(), - pendingOptions.getOnAnimationStartListener()); + pendingOptions.getAnimationStartedListener(), + pendingOptions.getAnimationFinishedListener()); break; case ANIM_CLIP_REVEAL: displayContent.mAppTransition.overridePendingAppTransitionClipReveal( @@ -3769,7 +3770,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final GraphicBuffer buffer = pendingOptions.getThumbnail(); displayContent.mAppTransition.overridePendingAppTransitionThumb(buffer, pendingOptions.getStartX(), pendingOptions.getStartY(), - pendingOptions.getOnAnimationStartListener(), + pendingOptions.getAnimationStartedListener(), scaleUp); if (intent.getSourceBounds() == null && buffer != null) { intent.setSourceBounds(new Rect(pendingOptions.getStartX(), @@ -3785,19 +3786,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pendingOptions.getSpecsFuture(); if (specsFuture != null) { displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture( - specsFuture, pendingOptions.getOnAnimationStartListener(), + specsFuture, pendingOptions.getAnimationStartedListener(), animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP); } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN && specs != null) { displayContent.mAppTransition.overridePendingAppTransitionMultiThumb( - specs, pendingOptions.getOnAnimationStartListener(), + specs, pendingOptions.getAnimationStartedListener(), pendingOptions.getAnimationFinishedListener(), false); } else { displayContent.mAppTransition.overridePendingAppTransitionAspectScaledThumb( pendingOptions.getThumbnail(), pendingOptions.getStartX(), pendingOptions.getStartY(), pendingOptions.getWidth(), pendingOptions.getHeight(), - pendingOptions.getOnAnimationStartListener(), + pendingOptions.getAnimationStartedListener(), (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP)); if (intent.getSourceBounds() == null) { intent.setSourceBounds(new Rect(pendingOptions.getStartX(), diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 682e991bdad27..44ab1e3140af1 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -2003,7 +2003,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (self.isState( ActivityStack.ActivityState.RESUMED, ActivityStack.ActivityState.PAUSING)) { self.getDisplay().mDisplayContent.mAppTransition.overridePendingAppTransition( - packageName, enterAnim, exitAnim, null); + packageName, enterAnim, exitAnim, null, null); } Binder.restoreCallingIdentity(origId); diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index f86aeb2244dc7..755bc9ad82624 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -1411,23 +1411,7 @@ public class AppTransition implements Dump { : new TranslateAnimation(0, fromX, 0, fromY); set.addAnimation(scale); set.addAnimation(translation); - - final IRemoteCallback callback = mAnimationFinishedCallback; - if (callback != null) { - set.setAnimationListener(new Animation.AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { } - - @Override - public void onAnimationEnd(Animation animation) { - mHandler.sendMessage(PooledLambda.obtainMessage( - AppTransition::doAnimationCallback, callback)); - } - - @Override - public void onAnimationRepeat(Animation animation) { } - }); - } + setAppTransitionFinishedCallbackIfNeeded(set); return set; } @@ -1665,6 +1649,7 @@ public class AppTransition implements Dump { "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s " + "isEntrance=%b Callers=%s", a, appTransitionToString(transit), enter, Debug.getCallers(3)); + setAppTransitionFinishedCallbackIfNeeded(a); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) { a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace); ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, @@ -1833,7 +1818,7 @@ public class AppTransition implements Dump { } void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, - IRemoteCallback startedCallback) { + IRemoteCallback startedCallback, IRemoteCallback endedCallback) { if (canOverridePendingAppTransition()) { clear(); mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM; @@ -1842,6 +1827,7 @@ public class AppTransition implements Dump { mNextAppTransitionExit = exitAnim; postAnimationCallback(); mNextAppTransitionCallback = startedCallback; + mAnimationFinishedCallback = endedCallback; } } @@ -2329,6 +2315,25 @@ public class AppTransition implements Dump { } } + private void setAppTransitionFinishedCallbackIfNeeded(Animation anim) { + final IRemoteCallback callback = mAnimationFinishedCallback; + if (callback != null && anim != null) { + anim.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { } + + @Override + public void onAnimationEnd(Animation animation) { + mHandler.sendMessage(PooledLambda.obtainMessage( + AppTransition::doAnimationCallback, callback)); + } + + @Override + public void onAnimationRepeat(Animation animation) { } + }); + } + } + void removeAppTransitionTimeoutCallbacks() { mHandler.removeCallbacks(mHandleAppTransitionTimeoutRunnable); }