1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app;
18 
19 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
20 import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
23 import static android.view.Display.INVALID_DISPLAY;
24 
25 import android.annotation.Nullable;
26 import android.annotation.RequiresPermission;
27 import android.annotation.TestApi;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.graphics.Bitmap;
32 import android.graphics.Bitmap.Config;
33 import android.graphics.GraphicBuffer;
34 import android.graphics.Rect;
35 import android.os.Bundle;
36 import android.os.Handler;
37 import android.os.IRemoteCallback;
38 import android.os.Parcelable;
39 import android.os.RemoteException;
40 import android.os.ResultReceiver;
41 import android.os.UserHandle;
42 import android.transition.Transition;
43 import android.transition.TransitionListenerAdapter;
44 import android.transition.TransitionManager;
45 import android.util.Pair;
46 import android.util.Slog;
47 import android.view.AppTransitionAnimationSpec;
48 import android.view.IAppTransitionAnimationSpecsFuture;
49 import android.view.RemoteAnimationAdapter;
50 import android.view.View;
51 import android.view.ViewGroup;
52 import android.view.Window;
53 
54 import java.util.ArrayList;
55 
56 /**
57  * Helper class for building an options Bundle that can be used with
58  * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
59  * Context.startActivity(Intent, Bundle)} and related methods.
60  */
61 public class ActivityOptions {
62     private static final String TAG = "ActivityOptions";
63 
64     /**
65      * A long in the extras delivered by {@link #requestUsageTimeReport} that contains
66      * the total time (in ms) the user spent in the app flow.
67      */
68     public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
69 
70     /**
71      * A Bundle in the extras delivered by {@link #requestUsageTimeReport} that contains
72      * detailed information about the time spent in each package associated with the app;
73      * each key is a package name, whose value is a long containing the time (in ms).
74      */
75     public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
76 
77     /**
78      * The package name that created the options.
79      * @hide
80      */
81     public static final String KEY_PACKAGE_NAME = "android:activity.packageName";
82 
83     /**
84      * The bounds (window size) that the activity should be launched in. Set to null explicitly for
85      * full screen. If the key is not found, previous bounds will be preserved.
86      * NOTE: This value is ignored on devices that don't have
87      * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or
88      * {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled.
89      * @hide
90      */
91     public static final String KEY_LAUNCH_BOUNDS = "android:activity.launchBounds";
92 
93     /**
94      * Type of animation that arguments specify.
95      * @hide
96      */
97     public static final String KEY_ANIM_TYPE = "android:activity.animType";
98 
99     /**
100      * Custom enter animation resource ID.
101      * @hide
102      */
103     public static final String KEY_ANIM_ENTER_RES_ID = "android:activity.animEnterRes";
104 
105     /**
106      * Custom exit animation resource ID.
107      * @hide
108      */
109     public static final String KEY_ANIM_EXIT_RES_ID = "android:activity.animExitRes";
110 
111     /**
112      * Custom in-place animation resource ID.
113      * @hide
114      */
115     public static final String KEY_ANIM_IN_PLACE_RES_ID = "android:activity.animInPlaceRes";
116 
117     /**
118      * Bitmap for thumbnail animation.
119      * @hide
120      */
121     public static final String KEY_ANIM_THUMBNAIL = "android:activity.animThumbnail";
122 
123     /**
124      * Start X position of thumbnail animation.
125      * @hide
126      */
127     public static final String KEY_ANIM_START_X = "android:activity.animStartX";
128 
129     /**
130      * Start Y position of thumbnail animation.
131      * @hide
132      */
133     public static final String KEY_ANIM_START_Y = "android:activity.animStartY";
134 
135     /**
136      * Initial width of the animation.
137      * @hide
138      */
139     public static final String KEY_ANIM_WIDTH = "android:activity.animWidth";
140 
141     /**
142      * Initial height of the animation.
143      * @hide
144      */
145     public static final String KEY_ANIM_HEIGHT = "android:activity.animHeight";
146 
147     /**
148      * Callback for when animation is started.
149      * @hide
150      */
151     public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener";
152 
153     /**
154      * Callback for when the last frame of the animation is played.
155      * @hide
156      */
157     private static final String KEY_ANIMATION_FINISHED_LISTENER =
158             "android:activity.animationFinishedListener";
159 
160     /**
161      * Descriptions of app transition animations to be played during the activity launch.
162      */
163     private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";
164 
165     /**
166      * Whether the activity should be launched into LockTask mode.
167      * @see #setLockTaskEnabled(boolean)
168      */
169     private static final String KEY_LOCK_TASK_MODE = "android:activity.lockTaskMode";
170 
171     /**
172      * The display id the activity should be launched into.
173      * @see #setLaunchDisplayId(int)
174      * @hide
175      */
176     private static final String KEY_LAUNCH_DISPLAY_ID = "android.activity.launchDisplayId";
177 
178     /**
179      * The windowing mode the activity should be launched into.
180      * @hide
181      */
182     private static final String KEY_LAUNCH_WINDOWING_MODE = "android.activity.windowingMode";
183 
184     /**
185      * The activity type the activity should be launched as.
186      * @hide
187      */
188     private static final String KEY_LAUNCH_ACTIVITY_TYPE = "android.activity.activityType";
189 
190     /**
191      * The task id the activity should be launched into.
192      * @hide
193      */
194     private static final String KEY_LAUNCH_TASK_ID = "android.activity.launchTaskId";
195 
196     /**
197      * See {@link #setTaskOverlay}.
198      * @hide
199      */
200     private static final String KEY_TASK_OVERLAY = "android.activity.taskOverlay";
201 
202     /**
203      * See {@link #setTaskOverlay}.
204      * @hide
205      */
206     private static final String KEY_TASK_OVERLAY_CAN_RESUME =
207             "android.activity.taskOverlayCanResume";
208 
209     /**
210      * See {@link #setAvoidMoveToFront()}.
211      * @hide
212      */
213     private static final String KEY_AVOID_MOVE_TO_FRONT = "android.activity.avoidMoveToFront";
214 
215     /**
216      * Where the split-screen-primary stack should be positioned.
217      * @hide
218      */
219     private static final String KEY_SPLIT_SCREEN_CREATE_MODE =
220             "android:activity.splitScreenCreateMode";
221 
222     /**
223      * Determines whether to disallow the outgoing activity from entering picture-in-picture as the
224      * result of a new activity being launched.
225      * @hide
226      */
227     private static final String KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING =
228             "android:activity.disallowEnterPictureInPictureWhileLaunching";
229 
230     /**
231      * For Activity transitions, the calling Activity's TransitionListener used to
232      * notify the called Activity when the shared element and the exit transitions
233      * complete.
234      */
235     private static final String KEY_TRANSITION_COMPLETE_LISTENER
236             = "android:activity.transitionCompleteListener";
237 
238     private static final String KEY_TRANSITION_IS_RETURNING
239             = "android:activity.transitionIsReturning";
240     private static final String KEY_TRANSITION_SHARED_ELEMENTS
241             = "android:activity.sharedElementNames";
242     private static final String KEY_RESULT_DATA = "android:activity.resultData";
243     private static final String KEY_RESULT_CODE = "android:activity.resultCode";
244     private static final String KEY_EXIT_COORDINATOR_INDEX
245             = "android:activity.exitCoordinatorIndex";
246 
247     private static final String KEY_USAGE_TIME_REPORT = "android:activity.usageTimeReport";
248     private static final String KEY_ROTATION_ANIMATION_HINT = "android:activity.rotationAnimationHint";
249 
250     private static final String KEY_INSTANT_APP_VERIFICATION_BUNDLE
251             = "android:instantapps.installerbundle";
252     private static final String KEY_SPECS_FUTURE = "android:activity.specsFuture";
253     private static final String KEY_REMOTE_ANIMATION_ADAPTER
254             = "android:activity.remoteAnimationAdapter";
255 
256     /** @hide */
257     public static final int ANIM_NONE = 0;
258     /** @hide */
259     public static final int ANIM_CUSTOM = 1;
260     /** @hide */
261     public static final int ANIM_SCALE_UP = 2;
262     /** @hide */
263     public static final int ANIM_THUMBNAIL_SCALE_UP = 3;
264     /** @hide */
265     public static final int ANIM_THUMBNAIL_SCALE_DOWN = 4;
266     /** @hide */
267     public static final int ANIM_SCENE_TRANSITION = 5;
268     /** @hide */
269     public static final int ANIM_DEFAULT = 6;
270     /** @hide */
271     public static final int ANIM_LAUNCH_TASK_BEHIND = 7;
272     /** @hide */
273     public static final int ANIM_THUMBNAIL_ASPECT_SCALE_UP = 8;
274     /** @hide */
275     public static final int ANIM_THUMBNAIL_ASPECT_SCALE_DOWN = 9;
276     /** @hide */
277     public static final int ANIM_CUSTOM_IN_PLACE = 10;
278     /** @hide */
279     public static final int ANIM_CLIP_REVEAL = 11;
280     /** @hide */
281     public static final int ANIM_OPEN_CROSS_PROFILE_APPS = 12;
282     /** @hide */
283     public static final int ANIM_REMOTE_ANIMATION = 13;
284 
285     private String mPackageName;
286     private Rect mLaunchBounds;
287     private int mAnimationType = ANIM_NONE;
288     private int mCustomEnterResId;
289     private int mCustomExitResId;
290     private int mCustomInPlaceResId;
291     private Bitmap mThumbnail;
292     private int mStartX;
293     private int mStartY;
294     private int mWidth;
295     private int mHeight;
296     private IRemoteCallback mAnimationStartedListener;
297     private IRemoteCallback mAnimationFinishedListener;
298     private ResultReceiver mTransitionReceiver;
299     private boolean mIsReturning;
300     private ArrayList<String> mSharedElementNames;
301     private Intent mResultData;
302     private int mResultCode;
303     private int mExitCoordinatorIndex;
304     private PendingIntent mUsageTimeReport;
305     private boolean mLockTaskMode = false;
306     private int mLaunchDisplayId = INVALID_DISPLAY;
307     @WindowConfiguration.WindowingMode
308     private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
309     @WindowConfiguration.ActivityType
310     private int mLaunchActivityType = ACTIVITY_TYPE_UNDEFINED;
311     private int mLaunchTaskId = -1;
312     private int mSplitScreenCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
313     private boolean mDisallowEnterPictureInPictureWhileLaunching;
314     private boolean mTaskOverlay;
315     private boolean mTaskOverlayCanResume;
316     private boolean mAvoidMoveToFront;
317     private AppTransitionAnimationSpec mAnimSpecs[];
318     private int mRotationAnimationHint = -1;
319     private Bundle mAppVerificationBundle;
320     private IAppTransitionAnimationSpecsFuture mSpecsFuture;
321     private RemoteAnimationAdapter mRemoteAnimationAdapter;
322 
323     /**
324      * Create an ActivityOptions specifying a custom animation to run when
325      * the activity is displayed.
326      *
327      * @param context Who is defining this.  This is the application that the
328      * animation resources will be loaded from.
329      * @param enterResId A resource ID of the animation resource to use for
330      * the incoming activity.  Use 0 for no animation.
331      * @param exitResId A resource ID of the animation resource to use for
332      * the outgoing activity.  Use 0 for no animation.
333      * @return Returns a new ActivityOptions object that you can use to
334      * supply these options as the options Bundle when starting an activity.
335      */
makeCustomAnimation(Context context, int enterResId, int exitResId)336     public static ActivityOptions makeCustomAnimation(Context context,
337             int enterResId, int exitResId) {
338         return makeCustomAnimation(context, enterResId, exitResId, null, null);
339     }
340 
341     /**
342      * Create an ActivityOptions specifying a custom animation to run when
343      * the activity is displayed.
344      *
345      * @param context Who is defining this.  This is the application that the
346      * animation resources will be loaded from.
347      * @param enterResId A resource ID of the animation resource to use for
348      * the incoming activity.  Use 0 for no animation.
349      * @param exitResId A resource ID of the animation resource to use for
350      * the outgoing activity.  Use 0 for no animation.
351      * @param handler If <var>listener</var> is non-null this must be a valid
352      * Handler on which to dispatch the callback; otherwise it should be null.
353      * @param listener Optional OnAnimationStartedListener to find out when the
354      * requested animation has started running.  If for some reason the animation
355      * is not executed, the callback will happen immediately.
356      * @return Returns a new ActivityOptions object that you can use to
357      * supply these options as the options Bundle when starting an activity.
358      * @hide
359      */
makeCustomAnimation(Context context, int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener)360     public static ActivityOptions makeCustomAnimation(Context context,
361             int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener) {
362         ActivityOptions opts = new ActivityOptions();
363         opts.mPackageName = context.getPackageName();
364         opts.mAnimationType = ANIM_CUSTOM;
365         opts.mCustomEnterResId = enterResId;
366         opts.mCustomExitResId = exitResId;
367         opts.setOnAnimationStartedListener(handler, listener);
368         return opts;
369     }
370 
371     /**
372      * Creates an ActivityOptions specifying a custom animation to run in place on an existing
373      * activity.
374      *
375      * @param context Who is defining this.  This is the application that the
376      * animation resources will be loaded from.
377      * @param animId A resource ID of the animation resource to use for
378      * the incoming activity.
379      * @return Returns a new ActivityOptions object that you can use to
380      * supply these options as the options Bundle when running an in-place animation.
381      * @hide
382      */
makeCustomInPlaceAnimation(Context context, int animId)383     public static ActivityOptions makeCustomInPlaceAnimation(Context context, int animId) {
384         if (animId == 0) {
385             throw new RuntimeException("You must specify a valid animation.");
386         }
387 
388         ActivityOptions opts = new ActivityOptions();
389         opts.mPackageName = context.getPackageName();
390         opts.mAnimationType = ANIM_CUSTOM_IN_PLACE;
391         opts.mCustomInPlaceResId = animId;
392         return opts;
393     }
394 
setOnAnimationStartedListener(final Handler handler, final OnAnimationStartedListener listener)395     private void setOnAnimationStartedListener(final Handler handler,
396             final OnAnimationStartedListener listener) {
397         if (listener != null) {
398             mAnimationStartedListener = new IRemoteCallback.Stub() {
399                 @Override
400                 public void sendResult(Bundle data) throws RemoteException {
401                     handler.post(new Runnable() {
402                         @Override public void run() {
403                             listener.onAnimationStarted();
404                         }
405                     });
406                 }
407             };
408         }
409     }
410 
411     /**
412      * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
413      * to find out when the given animation has started running.
414      * @hide
415      */
416     public interface OnAnimationStartedListener {
onAnimationStarted()417         void onAnimationStarted();
418     }
419 
setOnAnimationFinishedListener(final Handler handler, final OnAnimationFinishedListener listener)420     private void setOnAnimationFinishedListener(final Handler handler,
421             final OnAnimationFinishedListener listener) {
422         if (listener != null) {
423             mAnimationFinishedListener = new IRemoteCallback.Stub() {
424                 @Override
425                 public void sendResult(Bundle data) throws RemoteException {
426                     handler.post(new Runnable() {
427                         @Override
428                         public void run() {
429                             listener.onAnimationFinished();
430                         }
431                     });
432                 }
433             };
434         }
435     }
436 
437     /**
438      * Callback for use with {@link ActivityOptions#makeThumbnailAspectScaleDownAnimation}
439      * to find out when the given animation has drawn its last frame.
440      * @hide
441      */
442     public interface OnAnimationFinishedListener {
onAnimationFinished()443         void onAnimationFinished();
444     }
445 
446     /**
447      * Create an ActivityOptions specifying an animation where the new
448      * activity is scaled from a small originating area of the screen to
449      * its final full representation.
450      *
451      * <p>If the Intent this is being used with has not set its
452      * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
453      * those bounds will be filled in for you based on the initial
454      * bounds passed in here.
455      *
456      * @param source The View that the new activity is animating from.  This
457      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
458      * @param startX The x starting location of the new activity, relative to <var>source</var>.
459      * @param startY The y starting location of the activity, relative to <var>source</var>.
460      * @param width The initial width of the new activity.
461      * @param height The initial height of the new activity.
462      * @return Returns a new ActivityOptions object that you can use to
463      * supply these options as the options Bundle when starting an activity.
464      */
makeScaleUpAnimation(View source, int startX, int startY, int width, int height)465     public static ActivityOptions makeScaleUpAnimation(View source,
466             int startX, int startY, int width, int height) {
467         ActivityOptions opts = new ActivityOptions();
468         opts.mPackageName = source.getContext().getPackageName();
469         opts.mAnimationType = ANIM_SCALE_UP;
470         int[] pts = new int[2];
471         source.getLocationOnScreen(pts);
472         opts.mStartX = pts[0] + startX;
473         opts.mStartY = pts[1] + startY;
474         opts.mWidth = width;
475         opts.mHeight = height;
476         return opts;
477     }
478 
479     /**
480      * Create an ActivityOptions specifying an animation where the new
481      * activity is revealed from a small originating area of the screen to
482      * its final full representation.
483      *
484      * @param source The View that the new activity is animating from.  This
485      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
486      * @param startX The x starting location of the new activity, relative to <var>source</var>.
487      * @param startY The y starting location of the activity, relative to <var>source</var>.
488      * @param width The initial width of the new activity.
489      * @param height The initial height of the new activity.
490      * @return Returns a new ActivityOptions object that you can use to
491      * supply these options as the options Bundle when starting an activity.
492      */
makeClipRevealAnimation(View source, int startX, int startY, int width, int height)493     public static ActivityOptions makeClipRevealAnimation(View source,
494             int startX, int startY, int width, int height) {
495         ActivityOptions opts = new ActivityOptions();
496         opts.mAnimationType = ANIM_CLIP_REVEAL;
497         int[] pts = new int[2];
498         source.getLocationOnScreen(pts);
499         opts.mStartX = pts[0] + startX;
500         opts.mStartY = pts[1] + startY;
501         opts.mWidth = width;
502         opts.mHeight = height;
503         return opts;
504     }
505 
506     /**
507      * Creates an {@link ActivityOptions} object specifying an animation where the new activity
508      * is started in another user profile by calling {@link
509      * android.content.pm.crossprofile.CrossProfileApps#startMainActivity(ComponentName, UserHandle)
510      * }.
511      * @hide
512      */
makeOpenCrossProfileAppsAnimation()513     public static ActivityOptions makeOpenCrossProfileAppsAnimation() {
514         ActivityOptions options = new ActivityOptions();
515         options.mAnimationType = ANIM_OPEN_CROSS_PROFILE_APPS;
516         return options;
517     }
518 
519     /**
520      * Create an ActivityOptions specifying an animation where a thumbnail
521      * is scaled from a given position to the new activity window that is
522      * being started.
523      *
524      * <p>If the Intent this is being used with has not set its
525      * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
526      * those bounds will be filled in for you based on the initial
527      * thumbnail location and size provided here.
528      *
529      * @param source The View that this thumbnail is animating from.  This
530      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
531      * @param thumbnail The bitmap that will be shown as the initial thumbnail
532      * of the animation.
533      * @param startX The x starting location of the bitmap, relative to <var>source</var>.
534      * @param startY The y starting location of the bitmap, relative to <var>source</var>.
535      * @return Returns a new ActivityOptions object that you can use to
536      * supply these options as the options Bundle when starting an activity.
537      */
makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY)538     public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
539             Bitmap thumbnail, int startX, int startY) {
540         return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, null);
541     }
542 
543     /**
544      * Create an ActivityOptions specifying an animation where a thumbnail
545      * is scaled from a given position to the new activity window that is
546      * being started.
547      *
548      * @param source The View that this thumbnail is animating from.  This
549      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
550      * @param thumbnail The bitmap that will be shown as the initial thumbnail
551      * of the animation.
552      * @param startX The x starting location of the bitmap, relative to <var>source</var>.
553      * @param startY The y starting location of the bitmap, relative to <var>source</var>.
554      * @param listener Optional OnAnimationStartedListener to find out when the
555      * requested animation has started running.  If for some reason the animation
556      * is not executed, the callback will happen immediately.
557      * @return Returns a new ActivityOptions object that you can use to
558      * supply these options as the options Bundle when starting an activity.
559      */
makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener)560     private static ActivityOptions makeThumbnailScaleUpAnimation(View source,
561             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
562         return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true);
563     }
564 
makeThumbnailAnimation(View source, Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener, boolean scaleUp)565     private static ActivityOptions makeThumbnailAnimation(View source,
566             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
567             boolean scaleUp) {
568         ActivityOptions opts = new ActivityOptions();
569         opts.mPackageName = source.getContext().getPackageName();
570         opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN;
571         opts.mThumbnail = thumbnail;
572         int[] pts = new int[2];
573         source.getLocationOnScreen(pts);
574         opts.mStartX = pts[0] + startX;
575         opts.mStartY = pts[1] + startY;
576         opts.setOnAnimationStartedListener(source.getHandler(), listener);
577         return opts;
578     }
579 
580     /**
581      * Create an ActivityOptions specifying an animation where a list of activity windows and
582      * thumbnails are aspect scaled to/from a new location.
583      * @hide
584      */
makeMultiThumbFutureAspectScaleAnimation(Context context, Handler handler, IAppTransitionAnimationSpecsFuture specsFuture, OnAnimationStartedListener listener, boolean scaleUp)585     public static ActivityOptions makeMultiThumbFutureAspectScaleAnimation(Context context,
586             Handler handler, IAppTransitionAnimationSpecsFuture specsFuture,
587             OnAnimationStartedListener listener, boolean scaleUp) {
588         ActivityOptions opts = new ActivityOptions();
589         opts.mPackageName = context.getPackageName();
590         opts.mAnimationType = scaleUp
591                 ? ANIM_THUMBNAIL_ASPECT_SCALE_UP
592                 : ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
593         opts.mSpecsFuture = specsFuture;
594         opts.setOnAnimationStartedListener(handler, listener);
595         return opts;
596     }
597 
598     /**
599      * Create an ActivityOptions specifying an animation where the new activity
600      * window and a thumbnail is aspect-scaled to a new location.
601      *
602      * @param source The View that this thumbnail is animating to.  This
603      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
604      * @param thumbnail The bitmap that will be shown as the final thumbnail
605      * of the animation.
606      * @param startX The x end location of the bitmap, relative to <var>source</var>.
607      * @param startY The y end location of the bitmap, relative to <var>source</var>.
608      * @param handler If <var>listener</var> is non-null this must be a valid
609      * Handler on which to dispatch the callback; otherwise it should be null.
610      * @param listener Optional OnAnimationStartedListener to find out when the
611      * requested animation has started running.  If for some reason the animation
612      * is not executed, the callback will happen immediately.
613      * @return Returns a new ActivityOptions object that you can use to
614      * supply these options as the options Bundle when starting an activity.
615      * @hide
616      */
makeThumbnailAspectScaleDownAnimation(View source, Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight, Handler handler, OnAnimationStartedListener listener)617     public static ActivityOptions makeThumbnailAspectScaleDownAnimation(View source,
618             Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight,
619             Handler handler, OnAnimationStartedListener listener) {
620         return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY,
621                 targetWidth, targetHeight, handler, listener, false);
622     }
623 
makeAspectScaledThumbnailAnimation(View source, Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight, Handler handler, OnAnimationStartedListener listener, boolean scaleUp)624     private static ActivityOptions makeAspectScaledThumbnailAnimation(View source, Bitmap thumbnail,
625             int startX, int startY, int targetWidth, int targetHeight,
626             Handler handler, OnAnimationStartedListener listener, boolean scaleUp) {
627         ActivityOptions opts = new ActivityOptions();
628         opts.mPackageName = source.getContext().getPackageName();
629         opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_ASPECT_SCALE_UP :
630                 ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
631         opts.mThumbnail = thumbnail;
632         int[] pts = new int[2];
633         source.getLocationOnScreen(pts);
634         opts.mStartX = pts[0] + startX;
635         opts.mStartY = pts[1] + startY;
636         opts.mWidth = targetWidth;
637         opts.mHeight = targetHeight;
638         opts.setOnAnimationStartedListener(handler, listener);
639         return opts;
640     }
641 
642     /** @hide */
makeThumbnailAspectScaleDownAnimation(View source, AppTransitionAnimationSpec[] specs, Handler handler, OnAnimationStartedListener onAnimationStartedListener, OnAnimationFinishedListener onAnimationFinishedListener)643     public static ActivityOptions makeThumbnailAspectScaleDownAnimation(View source,
644             AppTransitionAnimationSpec[] specs, Handler handler,
645             OnAnimationStartedListener onAnimationStartedListener,
646             OnAnimationFinishedListener onAnimationFinishedListener) {
647         ActivityOptions opts = new ActivityOptions();
648         opts.mPackageName = source.getContext().getPackageName();
649         opts.mAnimationType = ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
650         opts.mAnimSpecs = specs;
651         opts.setOnAnimationStartedListener(handler, onAnimationStartedListener);
652         opts.setOnAnimationFinishedListener(handler, onAnimationFinishedListener);
653         return opts;
654     }
655 
656     /**
657      * Create an ActivityOptions to transition between Activities using cross-Activity scene
658      * animations. This method carries the position of one shared element to the started Activity.
659      * The position of <code>sharedElement</code> will be used as the epicenter for the
660      * exit Transition. The position of the shared element in the launched Activity will be the
661      * epicenter of its entering Transition.
662      *
663      * <p>This requires {@link android.view.Window#FEATURE_ACTIVITY_TRANSITIONS} to be
664      * enabled on the calling Activity to cause an exit transition. The same must be in
665      * the called Activity to get an entering transition.</p>
666      * @param activity The Activity whose window contains the shared elements.
667      * @param sharedElement The View to transition to the started Activity.
668      * @param sharedElementName The shared element name as used in the target Activity. This
669      *                          must not be null.
670      * @return Returns a new ActivityOptions object that you can use to
671      *         supply these options as the options Bundle when starting an activity.
672      * @see android.transition.Transition#setEpicenterCallback(
673      *          android.transition.Transition.EpicenterCallback)
674      */
makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName)675     public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
676             View sharedElement, String sharedElementName) {
677         return makeSceneTransitionAnimation(activity, Pair.create(sharedElement, sharedElementName));
678     }
679 
680     /**
681      * Create an ActivityOptions to transition between Activities using cross-Activity scene
682      * animations. This method carries the position of multiple shared elements to the started
683      * Activity. The position of the first element in sharedElements
684      * will be used as the epicenter for the exit Transition. The position of the associated
685      * shared element in the launched Activity will be the epicenter of its entering Transition.
686      *
687      * <p>This requires {@link android.view.Window#FEATURE_ACTIVITY_TRANSITIONS} to be
688      * enabled on the calling Activity to cause an exit transition. The same must be in
689      * the called Activity to get an entering transition.</p>
690      * @param activity The Activity whose window contains the shared elements.
691      * @param sharedElements The names of the shared elements to transfer to the called
692      *                       Activity and their associated Views. The Views must each have
693      *                       a unique shared element name.
694      * @return Returns a new ActivityOptions object that you can use to
695      *         supply these options as the options Bundle when starting an activity.
696      * @see android.transition.Transition#setEpicenterCallback(
697      *          android.transition.Transition.EpicenterCallback)
698      */
699     @SafeVarargs
makeSceneTransitionAnimation(Activity activity, Pair<View, String>... sharedElements)700     public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
701             Pair<View, String>... sharedElements) {
702         ActivityOptions opts = new ActivityOptions();
703         makeSceneTransitionAnimation(activity, activity.getWindow(), opts,
704                 activity.mExitTransitionListener, sharedElements);
705         return opts;
706     }
707 
708     /**
709      * Call this immediately prior to startActivity to begin a shared element transition
710      * from a non-Activity. The window must support Window.FEATURE_ACTIVITY_TRANSITIONS.
711      * The exit transition will start immediately and the shared element transition will
712      * start once the launched Activity's shared element is ready.
713      * <p>
714      * When all transitions have completed and the shared element has been transfered,
715      * the window's decor View will have its visibility set to View.GONE.
716      *
717      * @hide
718      */
719     @SafeVarargs
startSharedElementAnimation(Window window, Pair<View, String>... sharedElements)720     public static ActivityOptions startSharedElementAnimation(Window window,
721             Pair<View, String>... sharedElements) {
722         ActivityOptions opts = new ActivityOptions();
723         final View decorView = window.getDecorView();
724         if (decorView == null) {
725             return opts;
726         }
727         final ExitTransitionCoordinator exit =
728                 makeSceneTransitionAnimation(null, window, opts, null, sharedElements);
729         if (exit != null) {
730             HideWindowListener listener = new HideWindowListener(window, exit);
731             exit.setHideSharedElementsCallback(listener);
732             exit.startExit();
733         }
734         return opts;
735     }
736 
737     /**
738      * This method should be called when the {@link #startSharedElementAnimation(Window, Pair[])}
739      * animation must be stopped and the Views reset. This can happen if there was an error
740      * from startActivity or a springboard activity and the animation should stop and reset.
741      *
742      * @hide
743      */
stopSharedElementAnimation(Window window)744     public static void stopSharedElementAnimation(Window window) {
745         final View decorView = window.getDecorView();
746         if (decorView == null) {
747             return;
748         }
749         final ExitTransitionCoordinator exit = (ExitTransitionCoordinator)
750                 decorView.getTag(com.android.internal.R.id.cross_task_transition);
751         if (exit != null) {
752             exit.cancelPendingTransitions();
753             decorView.setTagInternal(com.android.internal.R.id.cross_task_transition, null);
754             TransitionManager.endTransitions((ViewGroup) decorView);
755             exit.resetViews();
756             exit.clearState();
757             decorView.setVisibility(View.VISIBLE);
758         }
759     }
760 
makeSceneTransitionAnimation(Activity activity, Window window, ActivityOptions opts, SharedElementCallback callback, Pair<View, String>[] sharedElements)761     static ExitTransitionCoordinator makeSceneTransitionAnimation(Activity activity, Window window,
762             ActivityOptions opts, SharedElementCallback callback,
763             Pair<View, String>[] sharedElements) {
764         if (!window.hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) {
765             opts.mAnimationType = ANIM_DEFAULT;
766             return null;
767         }
768         opts.mAnimationType = ANIM_SCENE_TRANSITION;
769 
770         ArrayList<String> names = new ArrayList<String>();
771         ArrayList<View> views = new ArrayList<View>();
772 
773         if (sharedElements != null) {
774             for (int i = 0; i < sharedElements.length; i++) {
775                 Pair<View, String> sharedElement = sharedElements[i];
776                 String sharedElementName = sharedElement.second;
777                 if (sharedElementName == null) {
778                     throw new IllegalArgumentException("Shared element name must not be null");
779                 }
780                 names.add(sharedElementName);
781                 View view = sharedElement.first;
782                 if (view == null) {
783                     throw new IllegalArgumentException("Shared element must not be null");
784                 }
785                 views.add(sharedElement.first);
786             }
787         }
788 
789         ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, window,
790                 callback, names, names, views, false);
791         opts.mTransitionReceiver = exit;
792         opts.mSharedElementNames = names;
793         opts.mIsReturning = (activity == null);
794         if (activity == null) {
795             opts.mExitCoordinatorIndex = -1;
796         } else {
797             opts.mExitCoordinatorIndex =
798                     activity.mActivityTransitionState.addExitTransitionCoordinator(exit);
799         }
800         return exit;
801     }
802 
803     /** @hide */
makeSceneTransitionAnimation(Activity activity, ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames, int resultCode, Intent resultData)804     static ActivityOptions makeSceneTransitionAnimation(Activity activity,
805             ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames,
806             int resultCode, Intent resultData) {
807         ActivityOptions opts = new ActivityOptions();
808         opts.mAnimationType = ANIM_SCENE_TRANSITION;
809         opts.mSharedElementNames = sharedElementNames;
810         opts.mTransitionReceiver = exitCoordinator;
811         opts.mIsReturning = true;
812         opts.mResultCode = resultCode;
813         opts.mResultData = resultData;
814         opts.mExitCoordinatorIndex =
815                 activity.mActivityTransitionState.addExitTransitionCoordinator(exitCoordinator);
816         return opts;
817     }
818 
819     /**
820      * If set along with Intent.FLAG_ACTIVITY_NEW_DOCUMENT then the task being launched will not be
821      * presented to the user but will instead be only available through the recents task list.
822      * In addition, the new task wil be affiliated with the launching activity's task.
823      * Affiliated tasks are grouped together in the recents task list.
824      *
825      * <p>This behavior is not supported for activities with {@link
826      * android.R.styleable#AndroidManifestActivity_launchMode launchMode} values of
827      * <code>singleInstance</code> or <code>singleTask</code>.
828      */
makeTaskLaunchBehind()829     public static ActivityOptions makeTaskLaunchBehind() {
830         final ActivityOptions opts = new ActivityOptions();
831         opts.mAnimationType = ANIM_LAUNCH_TASK_BEHIND;
832         return opts;
833     }
834 
835     /**
836      * Create a basic ActivityOptions that has no special animation associated with it.
837      * Other options can still be set.
838      */
makeBasic()839     public static ActivityOptions makeBasic() {
840         final ActivityOptions opts = new ActivityOptions();
841         return opts;
842     }
843 
844     /**
845      * Create an {@link ActivityOptions} instance that lets the application control the entire
846      * animation using a {@link RemoteAnimationAdapter}.
847      * @hide
848      */
849     @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
makeRemoteAnimation( RemoteAnimationAdapter remoteAnimationAdapter)850     public static ActivityOptions makeRemoteAnimation(
851             RemoteAnimationAdapter remoteAnimationAdapter) {
852         final ActivityOptions opts = new ActivityOptions();
853         opts.mRemoteAnimationAdapter = remoteAnimationAdapter;
854         opts.mAnimationType = ANIM_REMOTE_ANIMATION;
855         return opts;
856     }
857 
858     /** @hide */
getLaunchTaskBehind()859     public boolean getLaunchTaskBehind() {
860         return mAnimationType == ANIM_LAUNCH_TASK_BEHIND;
861     }
862 
ActivityOptions()863     private ActivityOptions() {
864     }
865 
866     /** @hide */
ActivityOptions(Bundle opts)867     public ActivityOptions(Bundle opts) {
868         // If the remote side sent us bad parcelables, they won't get the
869         // results they want, which is their loss.
870         opts.setDefusable(true);
871 
872         mPackageName = opts.getString(KEY_PACKAGE_NAME);
873         try {
874             mUsageTimeReport = opts.getParcelable(KEY_USAGE_TIME_REPORT);
875         } catch (RuntimeException e) {
876             Slog.w(TAG, e);
877         }
878         mLaunchBounds = opts.getParcelable(KEY_LAUNCH_BOUNDS);
879         mAnimationType = opts.getInt(KEY_ANIM_TYPE);
880         switch (mAnimationType) {
881             case ANIM_CUSTOM:
882                 mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
883                 mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
884                 mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
885                         opts.getBinder(KEY_ANIM_START_LISTENER));
886                 break;
887 
888             case ANIM_CUSTOM_IN_PLACE:
889                 mCustomInPlaceResId = opts.getInt(KEY_ANIM_IN_PLACE_RES_ID, 0);
890                 break;
891 
892             case ANIM_SCALE_UP:
893             case ANIM_CLIP_REVEAL:
894                 mStartX = opts.getInt(KEY_ANIM_START_X, 0);
895                 mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
896                 mWidth = opts.getInt(KEY_ANIM_WIDTH, 0);
897                 mHeight = opts.getInt(KEY_ANIM_HEIGHT, 0);
898                 break;
899 
900             case ANIM_THUMBNAIL_SCALE_UP:
901             case ANIM_THUMBNAIL_SCALE_DOWN:
902             case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
903             case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
904                 // Unpackage the GraphicBuffer from the parceled thumbnail
905                 final GraphicBuffer buffer = opts.getParcelable(KEY_ANIM_THUMBNAIL);
906                 if (buffer != null) {
907                     mThumbnail = Bitmap.createHardwareBitmap(buffer);
908                 }
909                 mStartX = opts.getInt(KEY_ANIM_START_X, 0);
910                 mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
911                 mWidth = opts.getInt(KEY_ANIM_WIDTH, 0);
912                 mHeight = opts.getInt(KEY_ANIM_HEIGHT, 0);
913                 mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
914                         opts.getBinder(KEY_ANIM_START_LISTENER));
915                 break;
916 
917             case ANIM_SCENE_TRANSITION:
918                 mTransitionReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
919                 mIsReturning = opts.getBoolean(KEY_TRANSITION_IS_RETURNING, false);
920                 mSharedElementNames = opts.getStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS);
921                 mResultData = opts.getParcelable(KEY_RESULT_DATA);
922                 mResultCode = opts.getInt(KEY_RESULT_CODE);
923                 mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
924                 break;
925         }
926         mLockTaskMode = opts.getBoolean(KEY_LOCK_TASK_MODE, false);
927         mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY);
928         mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
929         mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
930         mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
931         mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
932         mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
933         mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
934         mSplitScreenCreateMode = opts.getInt(KEY_SPLIT_SCREEN_CREATE_MODE,
935                 SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
936         mDisallowEnterPictureInPictureWhileLaunching = opts.getBoolean(
937                 KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING, false);
938         if (opts.containsKey(KEY_ANIM_SPECS)) {
939             Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS);
940             mAnimSpecs = new AppTransitionAnimationSpec[specs.length];
941             for (int i = specs.length - 1; i >= 0; i--) {
942                 mAnimSpecs[i] = (AppTransitionAnimationSpec) specs[i];
943             }
944         }
945         if (opts.containsKey(KEY_ANIMATION_FINISHED_LISTENER)) {
946             mAnimationFinishedListener = IRemoteCallback.Stub.asInterface(
947                     opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER));
948         }
949         mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT);
950         mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE);
951         if (opts.containsKey(KEY_SPECS_FUTURE)) {
952             mSpecsFuture = IAppTransitionAnimationSpecsFuture.Stub.asInterface(opts.getBinder(
953                     KEY_SPECS_FUTURE));
954         }
955         mRemoteAnimationAdapter = opts.getParcelable(KEY_REMOTE_ANIMATION_ADAPTER);
956     }
957 
958     /**
959      * Sets the bounds (window size) that the activity should be launched in.
960      * Rect position should be provided in pixels and in screen coordinates.
961      * Set to null explicitly for fullscreen.
962      * <p>
963      * <strong>NOTE:<strong/> This value is ignored on devices that don't have
964      * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or
965      * {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled.
966      * @param screenSpacePixelRect Launch bounds to use for the activity or null for fullscreen.
967      */
setLaunchBounds(@ullable Rect screenSpacePixelRect)968     public ActivityOptions setLaunchBounds(@Nullable Rect screenSpacePixelRect) {
969         mLaunchBounds = screenSpacePixelRect != null ? new Rect(screenSpacePixelRect) : null;
970         return this;
971     }
972 
973     /** @hide */
getPackageName()974     public String getPackageName() {
975         return mPackageName;
976     }
977 
978     /**
979      * Returns the bounds that should be used to launch the activity.
980      * @see #setLaunchBounds(Rect)
981      * @return Bounds used to launch the activity.
982      */
983     @Nullable
getLaunchBounds()984     public Rect getLaunchBounds() {
985         return mLaunchBounds;
986     }
987 
988     /** @hide */
getAnimationType()989     public int getAnimationType() {
990         return mAnimationType;
991     }
992 
993     /** @hide */
getCustomEnterResId()994     public int getCustomEnterResId() {
995         return mCustomEnterResId;
996     }
997 
998     /** @hide */
getCustomExitResId()999     public int getCustomExitResId() {
1000         return mCustomExitResId;
1001     }
1002 
1003     /** @hide */
getCustomInPlaceResId()1004     public int getCustomInPlaceResId() {
1005         return mCustomInPlaceResId;
1006     }
1007 
1008     /**
1009      * The thumbnail is copied into a hardware bitmap when it is bundled and sent to the system, so
1010      * it should always be backed by a GraphicBuffer on the other end.
1011      *
1012      * @hide
1013      */
getThumbnail()1014     public GraphicBuffer getThumbnail() {
1015         return mThumbnail != null ? mThumbnail.createGraphicBufferHandle() : null;
1016     }
1017 
1018     /** @hide */
getStartX()1019     public int getStartX() {
1020         return mStartX;
1021     }
1022 
1023     /** @hide */
getStartY()1024     public int getStartY() {
1025         return mStartY;
1026     }
1027 
1028     /** @hide */
getWidth()1029     public int getWidth() {
1030         return mWidth;
1031     }
1032 
1033     /** @hide */
getHeight()1034     public int getHeight() {
1035         return mHeight;
1036     }
1037 
1038     /** @hide */
getOnAnimationStartListener()1039     public IRemoteCallback getOnAnimationStartListener() {
1040         return mAnimationStartedListener;
1041     }
1042 
1043     /** @hide */
getAnimationFinishedListener()1044     public IRemoteCallback getAnimationFinishedListener() {
1045         return mAnimationFinishedListener;
1046     }
1047 
1048     /** @hide */
getExitCoordinatorKey()1049     public int getExitCoordinatorKey() { return mExitCoordinatorIndex; }
1050 
1051     /** @hide */
abort()1052     public void abort() {
1053         if (mAnimationStartedListener != null) {
1054             try {
1055                 mAnimationStartedListener.sendResult(null);
1056             } catch (RemoteException e) {
1057             }
1058         }
1059     }
1060 
1061     /** @hide */
isReturning()1062     public boolean isReturning() {
1063         return mIsReturning;
1064     }
1065 
1066     /**
1067      * Returns whether or not the ActivityOptions was created with
1068      * {@link #startSharedElementAnimation(Window, Pair[])}.
1069      *
1070      * @hide
1071      */
isCrossTask()1072     boolean isCrossTask() {
1073         return mExitCoordinatorIndex < 0;
1074     }
1075 
1076     /** @hide */
getSharedElementNames()1077     public ArrayList<String> getSharedElementNames() {
1078         return mSharedElementNames;
1079     }
1080 
1081     /** @hide */
getResultReceiver()1082     public ResultReceiver getResultReceiver() { return mTransitionReceiver; }
1083 
1084     /** @hide */
getResultCode()1085     public int getResultCode() { return mResultCode; }
1086 
1087     /** @hide */
getResultData()1088     public Intent getResultData() { return mResultData; }
1089 
1090     /** @hide */
getUsageTimeReport()1091     public PendingIntent getUsageTimeReport() {
1092         return mUsageTimeReport;
1093     }
1094 
1095     /** @hide */
getAnimSpecs()1096     public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; }
1097 
1098     /** @hide */
getSpecsFuture()1099     public IAppTransitionAnimationSpecsFuture getSpecsFuture() {
1100         return mSpecsFuture;
1101     }
1102 
1103     /** @hide */
getRemoteAnimationAdapter()1104     public RemoteAnimationAdapter getRemoteAnimationAdapter() {
1105         return mRemoteAnimationAdapter;
1106     }
1107 
1108     /** @hide */
setRemoteAnimationAdapter(RemoteAnimationAdapter remoteAnimationAdapter)1109     public void setRemoteAnimationAdapter(RemoteAnimationAdapter remoteAnimationAdapter) {
1110         mRemoteAnimationAdapter = remoteAnimationAdapter;
1111     }
1112 
1113     /** @hide */
fromBundle(Bundle bOptions)1114     public static ActivityOptions fromBundle(Bundle bOptions) {
1115         return bOptions != null ? new ActivityOptions(bOptions) : null;
1116     }
1117 
1118     /** @hide */
abort(ActivityOptions options)1119     public static void abort(ActivityOptions options) {
1120         if (options != null) {
1121             options.abort();
1122         }
1123     }
1124 
1125     /**
1126      * Gets whether the activity is to be launched into LockTask mode.
1127      * @return {@code true} if the activity is to be launched into LockTask mode.
1128      * @see Activity#startLockTask()
1129      * @see android.app.admin.DevicePolicyManager#setLockTaskPackages(ComponentName, String[])
1130      */
getLockTaskMode()1131     public boolean getLockTaskMode() {
1132         return mLockTaskMode;
1133     }
1134 
1135     /**
1136      * Sets whether the activity is to be launched into LockTask mode.
1137      *
1138      * Use this option to start an activity in LockTask mode. Note that only apps permitted by
1139      * {@link android.app.admin.DevicePolicyManager} can run in LockTask mode. Therefore, if
1140      * {@link android.app.admin.DevicePolicyManager#isLockTaskPermitted(String)} returns
1141      * {@code false} for the package of the target activity, a {@link SecurityException} will be
1142      * thrown during {@link Context#startActivity(Intent, Bundle)}. This method doesn't affect
1143      * activities that are already running — relaunch the activity to run in lock task mode.
1144      *
1145      * Defaults to {@code false} if not set.
1146      *
1147      * @param lockTaskMode {@code true} if the activity is to be launched into LockTask mode.
1148      * @return {@code this} {@link ActivityOptions} instance.
1149      * @see Activity#startLockTask()
1150      * @see android.app.admin.DevicePolicyManager#setLockTaskPackages(ComponentName, String[])
1151      */
setLockTaskEnabled(boolean lockTaskMode)1152     public ActivityOptions setLockTaskEnabled(boolean lockTaskMode) {
1153         mLockTaskMode = lockTaskMode;
1154         return this;
1155     }
1156 
1157     /**
1158      * Gets the id of the display where activity should be launched.
1159      * @return The id of the display where activity should be launched,
1160      *         {@link android.view.Display#INVALID_DISPLAY} if not set.
1161      * @see #setLaunchDisplayId(int)
1162      */
getLaunchDisplayId()1163     public int getLaunchDisplayId() {
1164         return mLaunchDisplayId;
1165     }
1166 
1167     /**
1168      * Sets the id of the display where activity should be launched.
1169      * An app can launch activities on public displays or private displays that are owned by the app
1170      * or where an app already has activities. Otherwise, trying to launch on a private display
1171      * or providing an invalid display id will result in an exception.
1172      * <p>
1173      * Setting launch display id will be ignored on devices that don't have
1174      * {@link android.content.pm.PackageManager#FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS}.
1175      * @param launchDisplayId The id of the display where the activity should be launched.
1176      * @return {@code this} {@link ActivityOptions} instance.
1177      */
setLaunchDisplayId(int launchDisplayId)1178     public ActivityOptions setLaunchDisplayId(int launchDisplayId) {
1179         mLaunchDisplayId = launchDisplayId;
1180         return this;
1181     }
1182 
1183     /** @hide */
getLaunchWindowingMode()1184     public int getLaunchWindowingMode() {
1185         return mLaunchWindowingMode;
1186     }
1187 
1188     /**
1189      * Sets the windowing mode the activity should launch into. If the input windowing mode is
1190      * {@link android.app.WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} and the device
1191      * isn't currently in split-screen windowing mode, then the activity will be launched in
1192      * {@link android.app.WindowConfiguration#WINDOWING_MODE_FULLSCREEN} windowing mode. For clarity
1193      * on this you can use
1194      * {@link android.app.WindowConfiguration#WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY}
1195      *
1196      * @hide
1197      */
1198     @TestApi
setLaunchWindowingMode(int windowingMode)1199     public void setLaunchWindowingMode(int windowingMode) {
1200         mLaunchWindowingMode = windowingMode;
1201     }
1202 
1203     /** @hide */
getLaunchActivityType()1204     public int getLaunchActivityType() {
1205         return mLaunchActivityType;
1206     }
1207 
1208     /** @hide */
1209     @TestApi
setLaunchActivityType(int activityType)1210     public void setLaunchActivityType(int activityType) {
1211         mLaunchActivityType = activityType;
1212     }
1213 
1214     /**
1215      * Sets the task the activity will be launched in.
1216      * @hide
1217      */
1218     @TestApi
setLaunchTaskId(int taskId)1219     public void setLaunchTaskId(int taskId) {
1220         mLaunchTaskId = taskId;
1221     }
1222 
1223     /**
1224      * @hide
1225      */
getLaunchTaskId()1226     public int getLaunchTaskId() {
1227         return mLaunchTaskId;
1228     }
1229 
1230     /**
1231      * Set's whether the activity launched with this option should be a task overlay. That is the
1232      * activity will always be the top activity of the task.  If {@param canResume} is true, then
1233      * the task will also not be moved to the front of the stack.
1234      * @hide
1235      */
1236     @TestApi
setTaskOverlay(boolean taskOverlay, boolean canResume)1237     public void setTaskOverlay(boolean taskOverlay, boolean canResume) {
1238         mTaskOverlay = taskOverlay;
1239         mTaskOverlayCanResume = canResume;
1240     }
1241 
1242     /**
1243      * @hide
1244      */
getTaskOverlay()1245     public boolean getTaskOverlay() {
1246         return mTaskOverlay;
1247     }
1248 
1249     /**
1250      * @hide
1251      */
canTaskOverlayResume()1252     public boolean canTaskOverlayResume() {
1253         return mTaskOverlayCanResume;
1254     }
1255 
1256     /**
1257      * Sets whether the activity launched should not cause the activity stack it is contained in to
1258      * be moved to the front as a part of launching.
1259      *
1260      * @hide
1261      */
setAvoidMoveToFront()1262     public void setAvoidMoveToFront() {
1263         mAvoidMoveToFront = true;
1264     }
1265 
1266     /**
1267      * @return whether the activity launch should prevent moving the associated activity stack to
1268      *         the front.
1269      * @hide
1270      */
getAvoidMoveToFront()1271     public boolean getAvoidMoveToFront() {
1272         return mAvoidMoveToFront;
1273     }
1274 
1275     /** @hide */
getSplitScreenCreateMode()1276     public int getSplitScreenCreateMode() {
1277         return mSplitScreenCreateMode;
1278     }
1279 
1280     /** @hide */
setSplitScreenCreateMode(int splitScreenCreateMode)1281     public void setSplitScreenCreateMode(int splitScreenCreateMode) {
1282         mSplitScreenCreateMode = splitScreenCreateMode;
1283     }
1284 
1285     /** @hide */
setDisallowEnterPictureInPictureWhileLaunching(boolean disallow)1286     public void setDisallowEnterPictureInPictureWhileLaunching(boolean disallow) {
1287         mDisallowEnterPictureInPictureWhileLaunching = disallow;
1288     }
1289 
1290     /** @hide */
disallowEnterPictureInPictureWhileLaunching()1291     public boolean disallowEnterPictureInPictureWhileLaunching() {
1292         return mDisallowEnterPictureInPictureWhileLaunching;
1293     }
1294 
1295     /**
1296      * Update the current values in this ActivityOptions from those supplied
1297      * in <var>otherOptions</var>.  Any values
1298      * defined in <var>otherOptions</var> replace those in the base options.
1299      */
update(ActivityOptions otherOptions)1300     public void update(ActivityOptions otherOptions) {
1301         if (otherOptions.mPackageName != null) {
1302             mPackageName = otherOptions.mPackageName;
1303         }
1304         mUsageTimeReport = otherOptions.mUsageTimeReport;
1305         mTransitionReceiver = null;
1306         mSharedElementNames = null;
1307         mIsReturning = false;
1308         mResultData = null;
1309         mResultCode = 0;
1310         mExitCoordinatorIndex = 0;
1311         mAnimationType = otherOptions.mAnimationType;
1312         switch (otherOptions.mAnimationType) {
1313             case ANIM_CUSTOM:
1314                 mCustomEnterResId = otherOptions.mCustomEnterResId;
1315                 mCustomExitResId = otherOptions.mCustomExitResId;
1316                 mThumbnail = null;
1317                 if (mAnimationStartedListener != null) {
1318                     try {
1319                         mAnimationStartedListener.sendResult(null);
1320                     } catch (RemoteException e) {
1321                     }
1322                 }
1323                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
1324                 break;
1325             case ANIM_CUSTOM_IN_PLACE:
1326                 mCustomInPlaceResId = otherOptions.mCustomInPlaceResId;
1327                 break;
1328             case ANIM_SCALE_UP:
1329                 mStartX = otherOptions.mStartX;
1330                 mStartY = otherOptions.mStartY;
1331                 mWidth = otherOptions.mWidth;
1332                 mHeight = otherOptions.mHeight;
1333                 if (mAnimationStartedListener != null) {
1334                     try {
1335                         mAnimationStartedListener.sendResult(null);
1336                     } catch (RemoteException e) {
1337                     }
1338                 }
1339                 mAnimationStartedListener = null;
1340                 break;
1341             case ANIM_THUMBNAIL_SCALE_UP:
1342             case ANIM_THUMBNAIL_SCALE_DOWN:
1343             case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
1344             case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
1345                 mThumbnail = otherOptions.mThumbnail;
1346                 mStartX = otherOptions.mStartX;
1347                 mStartY = otherOptions.mStartY;
1348                 mWidth = otherOptions.mWidth;
1349                 mHeight = otherOptions.mHeight;
1350                 if (mAnimationStartedListener != null) {
1351                     try {
1352                         mAnimationStartedListener.sendResult(null);
1353                     } catch (RemoteException e) {
1354                     }
1355                 }
1356                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
1357                 break;
1358             case ANIM_SCENE_TRANSITION:
1359                 mTransitionReceiver = otherOptions.mTransitionReceiver;
1360                 mSharedElementNames = otherOptions.mSharedElementNames;
1361                 mIsReturning = otherOptions.mIsReturning;
1362                 mThumbnail = null;
1363                 mAnimationStartedListener = null;
1364                 mResultData = otherOptions.mResultData;
1365                 mResultCode = otherOptions.mResultCode;
1366                 mExitCoordinatorIndex = otherOptions.mExitCoordinatorIndex;
1367                 break;
1368         }
1369         mLockTaskMode = otherOptions.mLockTaskMode;
1370         mAnimSpecs = otherOptions.mAnimSpecs;
1371         mAnimationFinishedListener = otherOptions.mAnimationFinishedListener;
1372         mSpecsFuture = otherOptions.mSpecsFuture;
1373         mRemoteAnimationAdapter = otherOptions.mRemoteAnimationAdapter;
1374     }
1375 
1376     /**
1377      * Returns the created options as a Bundle, which can be passed to
1378      * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
1379      * Context.startActivity(Intent, Bundle)} and related methods.
1380      * Note that the returned Bundle is still owned by the ActivityOptions
1381      * object; you must not modify it, but can supply it to the startActivity
1382      * methods that take an options Bundle.
1383      */
toBundle()1384     public Bundle toBundle() {
1385         Bundle b = new Bundle();
1386         if (mPackageName != null) {
1387             b.putString(KEY_PACKAGE_NAME, mPackageName);
1388         }
1389         if (mLaunchBounds != null) {
1390             b.putParcelable(KEY_LAUNCH_BOUNDS, mLaunchBounds);
1391         }
1392         b.putInt(KEY_ANIM_TYPE, mAnimationType);
1393         if (mUsageTimeReport != null) {
1394             b.putParcelable(KEY_USAGE_TIME_REPORT, mUsageTimeReport);
1395         }
1396         switch (mAnimationType) {
1397             case ANIM_CUSTOM:
1398                 b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
1399                 b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
1400                 b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
1401                         != null ? mAnimationStartedListener.asBinder() : null);
1402                 break;
1403             case ANIM_CUSTOM_IN_PLACE:
1404                 b.putInt(KEY_ANIM_IN_PLACE_RES_ID, mCustomInPlaceResId);
1405                 break;
1406             case ANIM_SCALE_UP:
1407             case ANIM_CLIP_REVEAL:
1408                 b.putInt(KEY_ANIM_START_X, mStartX);
1409                 b.putInt(KEY_ANIM_START_Y, mStartY);
1410                 b.putInt(KEY_ANIM_WIDTH, mWidth);
1411                 b.putInt(KEY_ANIM_HEIGHT, mHeight);
1412                 break;
1413             case ANIM_THUMBNAIL_SCALE_UP:
1414             case ANIM_THUMBNAIL_SCALE_DOWN:
1415             case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
1416             case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
1417                 // Once we parcel the thumbnail for transfering over to the system, create a copy of
1418                 // the bitmap to a hardware bitmap and pass through the GraphicBuffer
1419                 if (mThumbnail != null) {
1420                     final Bitmap hwBitmap = mThumbnail.copy(Config.HARDWARE, false /* isMutable */);
1421                     if (hwBitmap != null) {
1422                         b.putParcelable(KEY_ANIM_THUMBNAIL, hwBitmap.createGraphicBufferHandle());
1423                     } else {
1424                         Slog.w(TAG, "Failed to copy thumbnail");
1425                     }
1426                 }
1427                 b.putInt(KEY_ANIM_START_X, mStartX);
1428                 b.putInt(KEY_ANIM_START_Y, mStartY);
1429                 b.putInt(KEY_ANIM_WIDTH, mWidth);
1430                 b.putInt(KEY_ANIM_HEIGHT, mHeight);
1431                 b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
1432                         != null ? mAnimationStartedListener.asBinder() : null);
1433                 break;
1434             case ANIM_SCENE_TRANSITION:
1435                 if (mTransitionReceiver != null) {
1436                     b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mTransitionReceiver);
1437                 }
1438                 b.putBoolean(KEY_TRANSITION_IS_RETURNING, mIsReturning);
1439                 b.putStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS, mSharedElementNames);
1440                 b.putParcelable(KEY_RESULT_DATA, mResultData);
1441                 b.putInt(KEY_RESULT_CODE, mResultCode);
1442                 b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
1443                 break;
1444         }
1445         b.putBoolean(KEY_LOCK_TASK_MODE, mLockTaskMode);
1446         b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
1447         b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
1448         b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType);
1449         b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
1450         b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
1451         b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume);
1452         b.putBoolean(KEY_AVOID_MOVE_TO_FRONT, mAvoidMoveToFront);
1453         b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode);
1454         b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING,
1455                 mDisallowEnterPictureInPictureWhileLaunching);
1456         if (mAnimSpecs != null) {
1457             b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
1458         }
1459         if (mAnimationFinishedListener != null) {
1460             b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder());
1461         }
1462         if (mSpecsFuture != null) {
1463             b.putBinder(KEY_SPECS_FUTURE, mSpecsFuture.asBinder());
1464         }
1465         b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
1466         if (mAppVerificationBundle != null) {
1467             b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle);
1468         }
1469         if (mRemoteAnimationAdapter != null) {
1470             b.putParcelable(KEY_REMOTE_ANIMATION_ADAPTER, mRemoteAnimationAdapter);
1471         }
1472         return b;
1473     }
1474 
1475     /**
1476      * Ask the the system track that time the user spends in the app being launched, and
1477      * report it back once done.  The report will be sent to the given receiver, with
1478      * the extras {@link #EXTRA_USAGE_TIME_REPORT} and {@link #EXTRA_USAGE_TIME_REPORT_PACKAGES}
1479      * filled in.
1480      *
1481      * <p>The time interval tracked is from launching this activity until the user leaves
1482      * that activity's flow.  They are considered to stay in the flow as long as
1483      * new activities are being launched or returned to from the original flow,
1484      * even if this crosses package or task boundaries.  For example, if the originator
1485      * starts an activity to view an image, and while there the user selects to share,
1486      * which launches their email app in a new task, and they complete the share, the
1487      * time during that entire operation will be included until they finally hit back from
1488      * the original image viewer activity.</p>
1489      *
1490      * <p>The user is considered to complete a flow once they switch to another
1491      * activity that is not part of the tracked flow.  This may happen, for example, by
1492      * using the notification shade, launcher, or recents to launch or switch to another
1493      * app.  Simply going in to these navigation elements does not break the flow (although
1494      * the launcher and recents stops time tracking of the session); it is the act of
1495      * going somewhere else that completes the tracking.</p>
1496      *
1497      * @param receiver A broadcast receiver that willl receive the report.
1498      */
requestUsageTimeReport(PendingIntent receiver)1499     public void requestUsageTimeReport(PendingIntent receiver) {
1500         mUsageTimeReport = receiver;
1501     }
1502 
1503     /**
1504      * Return the filtered options only meant to be seen by the target activity itself
1505      * @hide
1506      */
forTargetActivity()1507     public ActivityOptions forTargetActivity() {
1508         if (mAnimationType == ANIM_SCENE_TRANSITION) {
1509             final ActivityOptions result = new ActivityOptions();
1510             result.update(this);
1511             return result;
1512         }
1513 
1514         return null;
1515     }
1516 
1517     /**
1518      * Returns the rotation animation set by {@link setRotationAnimationHint} or -1
1519      * if unspecified.
1520      * @hide
1521      */
getRotationAnimationHint()1522     public int getRotationAnimationHint() {
1523         return mRotationAnimationHint;
1524     }
1525 
1526 
1527     /**
1528      * Set a rotation animation to be used if launching the activity
1529      * triggers an orientation change, or -1 to clear. See
1530      * {@link android.view.WindowManager.LayoutParams} for rotation
1531      * animation values.
1532      * @hide
1533      */
setRotationAnimationHint(int hint)1534     public void setRotationAnimationHint(int hint) {
1535         mRotationAnimationHint = hint;
1536     }
1537 
1538     /**
1539      * Pop the extra verification bundle for the installer.
1540      * This removes the bundle from the ActivityOptions to make sure the installer bundle
1541      * is only available once.
1542      * @hide
1543      */
popAppVerificationBundle()1544     public Bundle popAppVerificationBundle() {
1545         Bundle out = mAppVerificationBundle;
1546         mAppVerificationBundle = null;
1547         return out;
1548     }
1549 
1550     /**
1551      * Set the {@link Bundle} that is provided to the app installer for additional verification
1552      * if the call to {@link Context#startActivity} results in an app being installed.
1553      *
1554      * This Bundle is not provided to any other app besides the installer.
1555      */
setAppVerificationBundle(Bundle bundle)1556     public ActivityOptions setAppVerificationBundle(Bundle bundle) {
1557         mAppVerificationBundle = bundle;
1558         return this;
1559 
1560     }
1561 
1562     /** @hide */
1563     @Override
toString()1564     public String toString() {
1565         return "ActivityOptions(" + hashCode() + "), mPackageName=" + mPackageName
1566                 + ", mAnimationType=" + mAnimationType + ", mStartX=" + mStartX + ", mStartY="
1567                 + mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight;
1568     }
1569 
1570     private static class HideWindowListener extends TransitionListenerAdapter
1571         implements ExitTransitionCoordinator.HideSharedElementsCallback {
1572         private final Window mWindow;
1573         private final ExitTransitionCoordinator mExit;
1574         private final boolean mWaitingForTransition;
1575         private boolean mTransitionEnded;
1576         private boolean mSharedElementHidden;
1577         private ArrayList<View> mSharedElements;
1578 
HideWindowListener(Window window, ExitTransitionCoordinator exit)1579         public HideWindowListener(Window window, ExitTransitionCoordinator exit) {
1580             mWindow = window;
1581             mExit = exit;
1582             mSharedElements = new ArrayList<>(exit.mSharedElements);
1583             Transition transition = mWindow.getExitTransition();
1584             if (transition != null) {
1585                 transition.addListener(this);
1586                 mWaitingForTransition = true;
1587             } else {
1588                 mWaitingForTransition = false;
1589             }
1590             View decorView = mWindow.getDecorView();
1591             if (decorView != null) {
1592                 if (decorView.getTag(com.android.internal.R.id.cross_task_transition) != null) {
1593                     throw new IllegalStateException(
1594                             "Cannot start a transition while one is running");
1595                 }
1596                 decorView.setTagInternal(com.android.internal.R.id.cross_task_transition, exit);
1597             }
1598         }
1599 
1600         @Override
onTransitionEnd(Transition transition)1601         public void onTransitionEnd(Transition transition) {
1602             mTransitionEnded = true;
1603             hideWhenDone();
1604             transition.removeListener(this);
1605         }
1606 
1607         @Override
hideSharedElements()1608         public void hideSharedElements() {
1609             mSharedElementHidden = true;
1610             hideWhenDone();
1611         }
1612 
hideWhenDone()1613         private void hideWhenDone() {
1614             if (mSharedElementHidden && (!mWaitingForTransition || mTransitionEnded)) {
1615                 mExit.resetViews();
1616                 int numSharedElements = mSharedElements.size();
1617                 for (int i = 0; i < numSharedElements; i++) {
1618                     View view = mSharedElements.get(i);
1619                     view.requestLayout();
1620                 }
1621                 View decorView = mWindow.getDecorView();
1622                 if (decorView != null) {
1623                     decorView.setTagInternal(
1624                             com.android.internal.R.id.cross_task_transition, null);
1625                     decorView.setVisibility(View.GONE);
1626                 }
1627             }
1628         }
1629     }
1630 }
1631