OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / core / java / android / app / ActivityOptions.java
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      */
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      */
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      */
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
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 {
344         void onAnimationStarted();
345     }
346
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 {
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      */
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      */
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      */
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      */
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      */
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
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      */
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      */
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
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 */
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      */
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
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
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      */
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
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 */
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      */
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      */
784     public static ActivityOptions makeBasic() {
785         final ActivityOptions opts = new ActivityOptions();
786         return opts;
787     }
788
789     /** @hide */
790     public boolean getLaunchTaskBehind() {
791         return mAnimationType == ANIM_LAUNCH_TASK_BEHIND;
792     }
793
794     private ActivityOptions() {
795     }
796
797     /** @hide */
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      */
881     public ActivityOptions setLaunchBounds(@Nullable Rect screenSpacePixelRect) {
882         mLaunchBounds = screenSpacePixelRect != null ? new Rect(screenSpacePixelRect) : null;
883         return this;
884     }
885
886     /** @hide */
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
897     public Rect getLaunchBounds() {
898         return mLaunchBounds;
899     }
900
901     /** @hide */
902     public int getAnimationType() {
903         return mAnimationType;
904     }
905
906     /** @hide */
907     public int getCustomEnterResId() {
908         return mCustomEnterResId;
909     }
910
911     /** @hide */
912     public int getCustomExitResId() {
913         return mCustomExitResId;
914     }
915
916     /** @hide */
917     public int getCustomInPlaceResId() {
918         return mCustomInPlaceResId;
919     }
920
921     /** @hide */
922     public Bitmap getThumbnail() {
923         return mThumbnail;
924     }
925
926     /** @hide */
927     public int getStartX() {
928         return mStartX;
929     }
930
931     /** @hide */
932     public int getStartY() {
933         return mStartY;
934     }
935
936     /** @hide */
937     public int getWidth() {
938         return mWidth;
939     }
940
941     /** @hide */
942     public int getHeight() {
943         return mHeight;
944     }
945
946     /** @hide */
947     public IRemoteCallback getOnAnimationStartListener() {
948         return mAnimationStartedListener;
949     }
950
951     /** @hide */
952     public IRemoteCallback getAnimationFinishedListener() {
953         return mAnimationFinishedListener;
954     }
955
956     /** @hide */
957     public int getExitCoordinatorKey() { return mExitCoordinatorIndex; }
958
959     /** @hide */
960     public void abort() {
961         if (mAnimationStartedListener != null) {
962             try {
963                 mAnimationStartedListener.sendResult(null);
964             } catch (RemoteException e) {
965             }
966         }
967     }
968
969     /** @hide */
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      */
980     boolean isCrossTask() {
981         return mExitCoordinatorIndex < 0;
982     }
983
984     /** @hide */
985     public ArrayList<String> getSharedElementNames() {
986         return mSharedElementNames;
987     }
988
989     /** @hide */
990     public ResultReceiver getResultReceiver() { return mTransitionReceiver; }
991
992     /** @hide */
993     public int getResultCode() { return mResultCode; }
994
995     /** @hide */
996     public Intent getResultData() { return mResultData; }
997
998     /** @hide */
999     public PendingIntent getUsageTimeReport() {
1000         return mUsageTimeReport;
1001     }
1002
1003     /** @hide */
1004     public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; }
1005
1006     /** @hide */
1007     public static ActivityOptions fromBundle(Bundle bOptions) {
1008         return bOptions != null ? new ActivityOptions(bOptions) : null;
1009     }
1010
1011     /** @hide */
1012     public static void abort(ActivityOptions options) {
1013         if (options != null) {
1014             options.abort();
1015         }
1016     }
1017
1018     /** @hide */
1019     public int getLaunchStackId() {
1020         return mLaunchStackId;
1021     }
1022
1023     /** @hide */
1024     @TestApi
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      */
1033     public void setLaunchTaskId(int taskId) {
1034         mLaunchTaskId = taskId;
1035     }
1036
1037     /**
1038      * @hide
1039      */
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      */
1050     public void setTaskOverlay(boolean taskOverlay) {
1051         mTaskOverlay = taskOverlay;
1052     }
1053
1054     /**
1055      * @hide
1056      */
1057     public boolean getTaskOverlay() {
1058         return mTaskOverlay;
1059     }
1060
1061     /** @hide */
1062     public int getDockCreateMode() {
1063         return mDockCreateMode;
1064     }
1065
1066     /** @hide */
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      */
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      */
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      */
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      */
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      */
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      */
1286     public void setRotationAnimationHint(int hint) {
1287         mRotationAnimationHint = hint;
1288     }
1289
1290     /** @hide */
1291     @Override
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
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
1329         public void onTransitionEnd(Transition transition) {
1330             mTransitionEnded = true;
1331             hideWhenDone();
1332             transition.removeListener(this);
1333         }
1334
1335         @Override
1336         public void hideSharedElements() {
1337             mSharedElementHidden = true;
1338             hideWhenDone();
1339         }
1340
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 }