diff --git a/api/test-current.txt b/api/test-current.txt index 0dff41b6a99c4..43cd5029115ad 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 925b15deff29d..0129aabd49f82 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; @@ -379,7 +380,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); } /** @@ -413,6 +414,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. @@ -458,6 +491,7 @@ public class ActivityOptions { * to find out when the given animation has started running. * @hide */ + @TestApi public interface OnAnimationStartedListener { void onAnimationStarted(); } @@ -484,6 +518,7 @@ public class ActivityOptions { * to find out when the given animation has drawn its last frame. * @hide */ + @TestApi public interface OnAnimationFinishedListener { void onAnimationFinished(); } @@ -1100,7 +1135,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 a03beee3a32fd..7a5ff41b18d95 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3769,7 +3769,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( @@ -3799,7 +3800,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(), @@ -3815,19 +3816,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 d92f43b6890c7..409e6ff998748 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 6f1ddcd793a9e..c31d55c6cbde3 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -1417,23 +1417,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; } @@ -1671,6 +1655,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, @@ -1835,7 +1820,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; @@ -1844,6 +1829,7 @@ public class AppTransition implements Dump { mNextAppTransitionExit = exitAnim; postAnimationCallback(); mNextAppTransitionCallback = startedCallback; + mAnimationFinishedCallback = endedCallback; } } @@ -2331,6 +2317,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); }