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