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