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