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