ActivityOptions.java revision 90186c6d6e7589835db183f602fb48e23a759a87
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
17package android.app;
18
19import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
20
21import android.content.Context;
22import android.content.Intent;
23import android.graphics.Bitmap;
24import android.graphics.Rect;
25import android.os.Bundle;
26import android.os.Handler;
27import android.os.IRemoteCallback;
28import android.os.RemoteException;
29import android.os.ResultReceiver;
30import android.util.Pair;
31import android.util.Slog;
32import android.view.View;
33import android.view.Window;
34
35import java.util.ArrayList;
36
37/**
38 * Helper class for building an options Bundle that can be used with
39 * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
40 * Context.startActivity(Intent, Bundle)} and related methods.
41 */
42public class ActivityOptions {
43    private static final String TAG = "ActivityOptions";
44
45    /**
46     * A long in the extras delivered by {@link #requestUsageTimeReport} that contains
47     * the total time (in ms) the user spent in the app flow.
48     */
49    public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
50
51    /**
52     * A Bundle in the extras delivered by {@link #requestUsageTimeReport} that contains
53     * detailed information about the time spent in each package associated with the app;
54     * each key is a package name, whose value is a long containing the time (in ms).
55     */
56    public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
57
58    /**
59     * The package name that created the options.
60     * @hide
61     */
62    public static final String KEY_PACKAGE_NAME = "android:activity.packageName";
63
64    /**
65     * The bounds that the activity should be started in. Set to null explicitly
66     * for full screen. If the key is not found, previous bounds will be preserved.
67     * @hide
68     */
69    public static final String KEY_BOUNDS = "android:activity.bounds";
70
71    /**
72     * Type of animation that arguments specify.
73     * @hide
74     */
75    public static final String KEY_ANIM_TYPE = "android:activity.animType";
76
77    /**
78     * Custom enter animation resource ID.
79     * @hide
80     */
81    public static final String KEY_ANIM_ENTER_RES_ID = "android:activity.animEnterRes";
82
83    /**
84     * Custom exit animation resource ID.
85     * @hide
86     */
87    public static final String KEY_ANIM_EXIT_RES_ID = "android:activity.animExitRes";
88
89    /**
90     * Custom in-place animation resource ID.
91     * @hide
92     */
93    public static final String KEY_ANIM_IN_PLACE_RES_ID = "android:activity.animInPlaceRes";
94
95    /**
96     * Bitmap for thumbnail animation.
97     * @hide
98     */
99    public static final String KEY_ANIM_THUMBNAIL = "android:activity.animThumbnail";
100
101    /**
102     * Start X position of thumbnail animation.
103     * @hide
104     */
105    public static final String KEY_ANIM_START_X = "android:activity.animStartX";
106
107    /**
108     * Start Y position of thumbnail animation.
109     * @hide
110     */
111    public static final String KEY_ANIM_START_Y = "android:activity.animStartY";
112
113    /**
114     * Initial width of the animation.
115     * @hide
116     */
117    public static final String KEY_ANIM_WIDTH = "android:activity.animWidth";
118
119    /**
120     * Initial height of the animation.
121     * @hide
122     */
123    public static final String KEY_ANIM_HEIGHT = "android:activity.animHeight";
124
125    /**
126     * Callback for when animation is started.
127     * @hide
128     */
129    public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener";
130
131    /**
132     * Where the docked stack should be positioned.
133     * @hide
134     */
135    private static final String KEY_DOCK_CREATE_MODE = "android:activity.dockCreateMode";
136
137    /**
138     * For Activity transitions, the calling Activity's TransitionListener used to
139     * notify the called Activity when the shared element and the exit transitions
140     * complete.
141     */
142    private static final String KEY_TRANSITION_COMPLETE_LISTENER
143            = "android:activity.transitionCompleteListener";
144
145    private static final String KEY_TRANSITION_IS_RETURNING
146            = "android:activity.transitionIsReturning";
147    private static final String KEY_TRANSITION_SHARED_ELEMENTS
148            = "android:activity.sharedElementNames";
149    private static final String KEY_RESULT_DATA = "android:activity.resultData";
150    private static final String KEY_RESULT_CODE = "android:activity.resultCode";
151    private static final String KEY_EXIT_COORDINATOR_INDEX
152            = "android:activity.exitCoordinatorIndex";
153
154    private static final String KEY_USAGE_TIME_REPORT = "android:activity.usageTimeReport";
155
156    /** @hide */
157    public static final int ANIM_NONE = 0;
158    /** @hide */
159    public static final int ANIM_CUSTOM = 1;
160    /** @hide */
161    public static final int ANIM_SCALE_UP = 2;
162    /** @hide */
163    public static final int ANIM_THUMBNAIL_SCALE_UP = 3;
164    /** @hide */
165    public static final int ANIM_THUMBNAIL_SCALE_DOWN = 4;
166    /** @hide */
167    public static final int ANIM_SCENE_TRANSITION = 5;
168    /** @hide */
169    public static final int ANIM_DEFAULT = 6;
170    /** @hide */
171    public static final int ANIM_LAUNCH_TASK_BEHIND = 7;
172    /** @hide */
173    public static final int ANIM_THUMBNAIL_ASPECT_SCALE_UP = 8;
174    /** @hide */
175    public static final int ANIM_THUMBNAIL_ASPECT_SCALE_DOWN = 9;
176    /** @hide */
177    public static final int ANIM_CUSTOM_IN_PLACE = 10;
178    /** @hide */
179    public static final int ANIM_CLIP_REVEAL = 11;
180
181    private String mPackageName;
182    private boolean mHasBounds;
183    private Rect mBounds;
184    private int mAnimationType = ANIM_NONE;
185    private int mCustomEnterResId;
186    private int mCustomExitResId;
187    private int mCustomInPlaceResId;
188    private Bitmap mThumbnail;
189    private int mStartX;
190    private int mStartY;
191    private int mWidth;
192    private int mHeight;
193    private IRemoteCallback mAnimationStartedListener;
194    private ResultReceiver mTransitionReceiver;
195    private boolean mIsReturning;
196    private ArrayList<String> mSharedElementNames;
197    private Intent mResultData;
198    private int mResultCode;
199    private int mExitCoordinatorIndex;
200    private PendingIntent mUsageTimeReport;
201    private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
202
203    /**
204     * Create an ActivityOptions specifying a custom animation to run when
205     * the activity is displayed.
206     *
207     * @param context Who is defining this.  This is the application that the
208     * animation resources will be loaded from.
209     * @param enterResId A resource ID of the animation resource to use for
210     * the incoming activity.  Use 0 for no animation.
211     * @param exitResId A resource ID of the animation resource to use for
212     * the outgoing activity.  Use 0 for no animation.
213     * @return Returns a new ActivityOptions object that you can use to
214     * supply these options as the options Bundle when starting an activity.
215     */
216    public static ActivityOptions makeCustomAnimation(Context context,
217            int enterResId, int exitResId) {
218        return makeCustomAnimation(context, enterResId, exitResId, null, null);
219    }
220
221    /**
222     * Create an ActivityOptions specifying a custom animation to run when
223     * the activity is displayed.
224     *
225     * @param context Who is defining this.  This is the application that the
226     * animation resources will be loaded from.
227     * @param enterResId A resource ID of the animation resource to use for
228     * the incoming activity.  Use 0 for no animation.
229     * @param exitResId A resource ID of the animation resource to use for
230     * the outgoing activity.  Use 0 for no animation.
231     * @param handler If <var>listener</var> is non-null this must be a valid
232     * Handler on which to dispatch the callback; otherwise it should be null.
233     * @param listener Optional OnAnimationStartedListener to find out when the
234     * requested animation has started running.  If for some reason the animation
235     * is not executed, the callback will happen immediately.
236     * @return Returns a new ActivityOptions object that you can use to
237     * supply these options as the options Bundle when starting an activity.
238     * @hide
239     */
240    public static ActivityOptions makeCustomAnimation(Context context,
241            int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener) {
242        ActivityOptions opts = new ActivityOptions();
243        opts.mPackageName = context.getPackageName();
244        opts.mAnimationType = ANIM_CUSTOM;
245        opts.mCustomEnterResId = enterResId;
246        opts.mCustomExitResId = exitResId;
247        opts.setOnAnimationStartedListener(handler, listener);
248        return opts;
249    }
250
251    /**
252     * Creates an ActivityOptions specifying a custom animation to run in place on an existing
253     * activity.
254     *
255     * @param context Who is defining this.  This is the application that the
256     * animation resources will be loaded from.
257     * @param animId A resource ID of the animation resource to use for
258     * the incoming activity.
259     * @return Returns a new ActivityOptions object that you can use to
260     * supply these options as the options Bundle when running an in-place animation.
261     * @hide
262     */
263    public static ActivityOptions makeCustomInPlaceAnimation(Context context, int animId) {
264        if (animId == 0) {
265            throw new RuntimeException("You must specify a valid animation.");
266        }
267
268        ActivityOptions opts = new ActivityOptions();
269        opts.mPackageName = context.getPackageName();
270        opts.mAnimationType = ANIM_CUSTOM_IN_PLACE;
271        opts.mCustomInPlaceResId = animId;
272        return opts;
273    }
274
275    private void setOnAnimationStartedListener(Handler handler,
276            OnAnimationStartedListener listener) {
277        if (listener != null) {
278            final Handler h = handler;
279            final OnAnimationStartedListener finalListener = listener;
280            mAnimationStartedListener = new IRemoteCallback.Stub() {
281                @Override public void sendResult(Bundle data) throws RemoteException {
282                    h.post(new Runnable() {
283                        @Override public void run() {
284                            finalListener.onAnimationStarted();
285                        }
286                    });
287                }
288            };
289        }
290    }
291
292    /**
293     * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
294     * to find out when the given animation has started running.
295     * @hide
296     */
297    public interface OnAnimationStartedListener {
298        void onAnimationStarted();
299    }
300
301    /**
302     * Create an ActivityOptions specifying an animation where the new
303     * activity is scaled from a small originating area of the screen to
304     * its final full representation.
305     *
306     * <p>If the Intent this is being used with has not set its
307     * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
308     * those bounds will be filled in for you based on the initial
309     * bounds passed in here.
310     *
311     * @param source The View that the new activity is animating from.  This
312     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
313     * @param startX The x starting location of the new activity, relative to <var>source</var>.
314     * @param startY The y starting location of the activity, relative to <var>source</var>.
315     * @param width The initial width of the new activity.
316     * @param height The initial height of the new activity.
317     * @return Returns a new ActivityOptions object that you can use to
318     * supply these options as the options Bundle when starting an activity.
319     */
320    public static ActivityOptions makeScaleUpAnimation(View source,
321            int startX, int startY, int width, int height) {
322        ActivityOptions opts = new ActivityOptions();
323        opts.mPackageName = source.getContext().getPackageName();
324        opts.mAnimationType = ANIM_SCALE_UP;
325        int[] pts = new int[2];
326        source.getLocationOnScreen(pts);
327        opts.mStartX = pts[0] + startX;
328        opts.mStartY = pts[1] + startY;
329        opts.mWidth = width;
330        opts.mHeight = height;
331        return opts;
332    }
333
334    /**
335     * Create an ActivityOptions specifying an animation where the new
336     * activity is revealed from a small originating area of the screen to
337     * its final full representation.
338     *
339     * @param source The View that the new activity is animating from.  This
340     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
341     * @param startX The x starting location of the new activity, relative to <var>source</var>.
342     * @param startY The y starting location of the activity, relative to <var>source</var>.
343     * @param width The initial width of the new activity.
344     * @param height The initial height of the new activity.
345     * @return Returns a new ActivityOptions object that you can use to
346     * supply these options as the options Bundle when starting an activity.
347     */
348    public static ActivityOptions makeClipRevealAnimation(View source,
349            int startX, int startY, int width, int height) {
350        ActivityOptions opts = new ActivityOptions();
351        opts.mAnimationType = ANIM_CLIP_REVEAL;
352        int[] pts = new int[2];
353        source.getLocationOnScreen(pts);
354        opts.mStartX = pts[0] + startX;
355        opts.mStartY = pts[1] + startY;
356        opts.mWidth = width;
357        opts.mHeight = height;
358        return opts;
359    }
360
361    /**
362     * Create an ActivityOptions specifying an animation where a thumbnail
363     * is scaled from a given position to the new activity window that is
364     * being started.
365     *
366     * <p>If the Intent this is being used with has not set its
367     * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
368     * those bounds will be filled in for you based on the initial
369     * thumbnail location and size provided here.
370     *
371     * @param source The View that this thumbnail is animating from.  This
372     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
373     * @param thumbnail The bitmap that will be shown as the initial thumbnail
374     * of the animation.
375     * @param startX The x starting location of the bitmap, relative to <var>source</var>.
376     * @param startY The y starting location of the bitmap, relative to <var>source</var>.
377     * @return Returns a new ActivityOptions object that you can use to
378     * supply these options as the options Bundle when starting an activity.
379     */
380    public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
381            Bitmap thumbnail, int startX, int startY) {
382        return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, null);
383    }
384
385    /**
386     * Create an ActivityOptions specifying an animation where a thumbnail
387     * is scaled from a given position to the new activity window that is
388     * being started.
389     *
390     * @param source The View that this thumbnail is animating from.  This
391     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
392     * @param thumbnail The bitmap that will be shown as the initial thumbnail
393     * of the animation.
394     * @param startX The x starting location of the bitmap, relative to <var>source</var>.
395     * @param startY The y starting location of the bitmap, relative to <var>source</var>.
396     * @param listener Optional OnAnimationStartedListener to find out when the
397     * requested animation has started running.  If for some reason the animation
398     * is not executed, the callback will happen immediately.
399     * @return Returns a new ActivityOptions object that you can use to
400     * supply these options as the options Bundle when starting an activity.
401     * @hide
402     */
403    public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
404            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
405        return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true);
406    }
407
408    /**
409     * Create an ActivityOptions specifying an animation where an activity window
410     * is scaled from a given position to a thumbnail at a specified location.
411     *
412     * @param source The View that this thumbnail is animating to.  This
413     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
414     * @param thumbnail The bitmap that will be shown as the final thumbnail
415     * of the animation.
416     * @param startX The x end location of the bitmap, relative to <var>source</var>.
417     * @param startY The y end location of the bitmap, relative to <var>source</var>.
418     * @param listener Optional OnAnimationStartedListener to find out when the
419     * requested animation has started running.  If for some reason the animation
420     * is not executed, the callback will happen immediately.
421     * @return Returns a new ActivityOptions object that you can use to
422     * supply these options as the options Bundle when starting an activity.
423     * @hide
424     */
425    public static ActivityOptions makeThumbnailScaleDownAnimation(View source,
426            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
427        return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, false);
428    }
429
430    private static ActivityOptions makeThumbnailAnimation(View source,
431            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
432            boolean scaleUp) {
433        ActivityOptions opts = new ActivityOptions();
434        opts.mPackageName = source.getContext().getPackageName();
435        opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN;
436        opts.mThumbnail = thumbnail;
437        int[] pts = new int[2];
438        source.getLocationOnScreen(pts);
439        opts.mStartX = pts[0] + startX;
440        opts.mStartY = pts[1] + startY;
441        opts.setOnAnimationStartedListener(source.getHandler(), listener);
442        return opts;
443    }
444
445    /**
446     * Create an ActivityOptions specifying an animation where the new activity
447     * window and a thumbnail is aspect-scaled to a new location.
448     *
449     * @param source The View that this thumbnail is animating from.  This
450     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
451     * @param thumbnail The bitmap that will be shown as the initial thumbnail
452     * of the animation.
453     * @param startX The x starting location of the bitmap, relative to <var>source</var>.
454     * @param startY The y starting location of the bitmap, relative to <var>source</var>.
455     * @param handler If <var>listener</var> is non-null this must be a valid
456     * Handler on which to dispatch the callback; otherwise it should be null.
457     * @param listener Optional OnAnimationStartedListener to find out when the
458     * requested animation has started running.  If for some reason the animation
459     * is not executed, the callback will happen immediately.
460     * @return Returns a new ActivityOptions object that you can use to
461     * supply these options as the options Bundle when starting an activity.
462     * @hide
463     */
464    public static ActivityOptions makeThumbnailAspectScaleUpAnimation(View source,
465            Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight,
466            Handler handler, OnAnimationStartedListener listener) {
467        return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY,
468                targetWidth, targetHeight, handler, listener, true);
469    }
470
471    /**
472     * Create an ActivityOptions specifying an animation where the new activity
473     * window and a thumbnail is aspect-scaled to a new location.
474     *
475     * @param source The View that this thumbnail is animating to.  This
476     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
477     * @param thumbnail The bitmap that will be shown as the final thumbnail
478     * of the animation.
479     * @param startX The x end location of the bitmap, relative to <var>source</var>.
480     * @param startY The y end location of the bitmap, relative to <var>source</var>.
481     * @param handler If <var>listener</var> is non-null this must be a valid
482     * Handler on which to dispatch the callback; otherwise it should be null.
483     * @param listener Optional OnAnimationStartedListener to find out when the
484     * requested animation has started running.  If for some reason the animation
485     * is not executed, the callback will happen immediately.
486     * @return Returns a new ActivityOptions object that you can use to
487     * supply these options as the options Bundle when starting an activity.
488     * @hide
489     */
490    public static ActivityOptions makeThumbnailAspectScaleDownAnimation(View source,
491            Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight,
492            Handler handler, OnAnimationStartedListener listener) {
493        return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY,
494                targetWidth, targetHeight, handler, listener, false);
495    }
496
497    private static ActivityOptions makeAspectScaledThumbnailAnimation(View source, Bitmap thumbnail,
498            int startX, int startY, int targetWidth, int targetHeight,
499            Handler handler, OnAnimationStartedListener listener, boolean scaleUp) {
500        ActivityOptions opts = new ActivityOptions();
501        opts.mPackageName = source.getContext().getPackageName();
502        opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_ASPECT_SCALE_UP :
503                ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
504        opts.mThumbnail = thumbnail;
505        int[] pts = new int[2];
506        source.getLocationOnScreen(pts);
507        opts.mStartX = pts[0] + startX;
508        opts.mStartY = pts[1] + startY;
509        opts.mWidth = targetWidth;
510        opts.mHeight = targetHeight;
511        opts.setOnAnimationStartedListener(handler, listener);
512        return opts;
513    }
514
515    /**
516     * Create an ActivityOptions to transition between Activities using cross-Activity scene
517     * animations. This method carries the position of one shared element to the started Activity.
518     * The position of <code>sharedElement</code> will be used as the epicenter for the
519     * exit Transition. The position of the shared element in the launched Activity will be the
520     * epicenter of its entering Transition.
521     *
522     * <p>This requires {@link android.view.Window#FEATURE_ACTIVITY_TRANSITIONS} to be
523     * enabled on the calling Activity to cause an exit transition. The same must be in
524     * the called Activity to get an entering transition.</p>
525     * @param activity The Activity whose window contains the shared elements.
526     * @param sharedElement The View to transition to the started Activity.
527     * @param sharedElementName The shared element name as used in the target Activity. This
528     *                          must not be null.
529     * @return Returns a new ActivityOptions object that you can use to
530     *         supply these options as the options Bundle when starting an activity.
531     * @see android.transition.Transition#setEpicenterCallback(
532     *          android.transition.Transition.EpicenterCallback)
533     */
534    public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
535            View sharedElement, String sharedElementName) {
536        return makeSceneTransitionAnimation(activity, Pair.create(sharedElement, sharedElementName));
537    }
538
539    /**
540     * Create an ActivityOptions to transition between Activities using cross-Activity scene
541     * animations. This method carries the position of multiple shared elements to the started
542     * Activity. The position of the first element in sharedElements
543     * will be used as the epicenter for the exit Transition. The position of the associated
544     * shared element in the launched Activity will be the epicenter of its entering Transition.
545     *
546     * <p>This requires {@link android.view.Window#FEATURE_ACTIVITY_TRANSITIONS} to be
547     * enabled on the calling Activity to cause an exit transition. The same must be in
548     * the called Activity to get an entering transition.</p>
549     * @param activity The Activity whose window contains the shared elements.
550     * @param sharedElements The names of the shared elements to transfer to the called
551     *                       Activity and their associated Views. The Views must each have
552     *                       a unique shared element name.
553     * @return Returns a new ActivityOptions object that you can use to
554     *         supply these options as the options Bundle when starting an activity.
555     * @see android.transition.Transition#setEpicenterCallback(
556     *          android.transition.Transition.EpicenterCallback)
557     */
558    public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
559            Pair<View, String>... sharedElements) {
560        ActivityOptions opts = new ActivityOptions();
561        if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) {
562            opts.mAnimationType = ANIM_DEFAULT;
563            return opts;
564        }
565        opts.mAnimationType = ANIM_SCENE_TRANSITION;
566
567        ArrayList<String> names = new ArrayList<String>();
568        ArrayList<View> views = new ArrayList<View>();
569
570        if (sharedElements != null) {
571            for (int i = 0; i < sharedElements.length; i++) {
572                Pair<View, String> sharedElement = sharedElements[i];
573                String sharedElementName = sharedElement.second;
574                if (sharedElementName == null) {
575                    throw new IllegalArgumentException("Shared element name must not be null");
576                }
577                names.add(sharedElementName);
578                View view = sharedElement.first;
579                if (view == null) {
580                    throw new IllegalArgumentException("Shared element must not be null");
581                }
582                views.add(sharedElement.first);
583            }
584        }
585
586        ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, names, names,
587                views, false);
588        opts.mTransitionReceiver = exit;
589        opts.mSharedElementNames = names;
590        opts.mIsReturning = false;
591        opts.mExitCoordinatorIndex =
592                activity.mActivityTransitionState.addExitTransitionCoordinator(exit);
593        return opts;
594    }
595
596    /** @hide */
597    public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
598            ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames,
599            int resultCode, Intent resultData) {
600        ActivityOptions opts = new ActivityOptions();
601        opts.mAnimationType = ANIM_SCENE_TRANSITION;
602        opts.mSharedElementNames = sharedElementNames;
603        opts.mTransitionReceiver = exitCoordinator;
604        opts.mIsReturning = true;
605        opts.mResultCode = resultCode;
606        opts.mResultData = resultData;
607        opts.mExitCoordinatorIndex =
608                activity.mActivityTransitionState.addExitTransitionCoordinator(exitCoordinator);
609        return opts;
610    }
611
612    /**
613     * If set along with Intent.FLAG_ACTIVITY_NEW_DOCUMENT then the task being launched will not be
614     * presented to the user but will instead be only available through the recents task list.
615     * In addition, the new task wil be affiliated with the launching activity's task.
616     * Affiliated tasks are grouped together in the recents task list.
617     *
618     * <p>This behavior is not supported for activities with {@link
619     * android.R.styleable#AndroidManifestActivity_launchMode launchMode} values of
620     * <code>singleInstance</code> or <code>singleTask</code>.
621     */
622    public static ActivityOptions makeTaskLaunchBehind() {
623        final ActivityOptions opts = new ActivityOptions();
624        opts.mAnimationType = ANIM_LAUNCH_TASK_BEHIND;
625        return opts;
626    }
627
628    /**
629     * Create a basic ActivityOptions that has no special animation associated with it.
630     * Other options can still be set.
631     */
632    public static ActivityOptions makeBasic() {
633        final ActivityOptions opts = new ActivityOptions();
634        return opts;
635    }
636
637    /** @hide */
638    public boolean getLaunchTaskBehind() {
639        return mAnimationType == ANIM_LAUNCH_TASK_BEHIND;
640    }
641
642    private ActivityOptions() {
643    }
644
645    /** @hide */
646    public ActivityOptions(Bundle opts) {
647        mPackageName = opts.getString(KEY_PACKAGE_NAME);
648        try {
649            mUsageTimeReport = opts.getParcelable(KEY_USAGE_TIME_REPORT);
650        } catch (RuntimeException e) {
651            Slog.w(TAG, e);
652        }
653        mHasBounds = opts.containsKey(KEY_BOUNDS);
654        if (mHasBounds) {
655            mBounds = opts.getParcelable(KEY_BOUNDS);
656        }
657        mAnimationType = opts.getInt(KEY_ANIM_TYPE);
658        switch (mAnimationType) {
659            case ANIM_CUSTOM:
660                mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
661                mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
662                mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
663                        opts.getBinder(KEY_ANIM_START_LISTENER));
664                break;
665
666            case ANIM_CUSTOM_IN_PLACE:
667                mCustomInPlaceResId = opts.getInt(KEY_ANIM_IN_PLACE_RES_ID, 0);
668                break;
669
670            case ANIM_SCALE_UP:
671            case ANIM_CLIP_REVEAL:
672                mStartX = opts.getInt(KEY_ANIM_START_X, 0);
673                mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
674                mWidth = opts.getInt(KEY_ANIM_WIDTH, 0);
675                mHeight = opts.getInt(KEY_ANIM_HEIGHT, 0);
676                break;
677
678            case ANIM_THUMBNAIL_SCALE_UP:
679            case ANIM_THUMBNAIL_SCALE_DOWN:
680            case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
681            case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
682                mThumbnail = (Bitmap) opts.getParcelable(KEY_ANIM_THUMBNAIL);
683                mStartX = opts.getInt(KEY_ANIM_START_X, 0);
684                mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
685                mWidth = opts.getInt(KEY_ANIM_WIDTH, 0);
686                mHeight = opts.getInt(KEY_ANIM_HEIGHT, 0);
687                mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
688                        opts.getBinder(KEY_ANIM_START_LISTENER));
689                break;
690
691            case ANIM_SCENE_TRANSITION:
692                mTransitionReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
693                mIsReturning = opts.getBoolean(KEY_TRANSITION_IS_RETURNING, false);
694                mSharedElementNames = opts.getStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS);
695                mResultData = opts.getParcelable(KEY_RESULT_DATA);
696                mResultCode = opts.getInt(KEY_RESULT_CODE);
697                mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
698                break;
699        }
700        mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
701    }
702
703    /** @hide */
704    public ActivityOptions setBounds(Rect bounds) {
705        mHasBounds = true;
706        mBounds = bounds;
707        return this;
708    }
709
710    /** @hide */
711    public String getPackageName() {
712        return mPackageName;
713    }
714
715    /** @hide */
716    public boolean hasBounds() {
717        return mHasBounds;
718    }
719
720    /** @hide */
721    public Rect getBounds(){
722        return mBounds;
723    }
724
725    /** @hide */
726    public int getAnimationType() {
727        return mAnimationType;
728    }
729
730    /** @hide */
731    public int getCustomEnterResId() {
732        return mCustomEnterResId;
733    }
734
735    /** @hide */
736    public int getCustomExitResId() {
737        return mCustomExitResId;
738    }
739
740    /** @hide */
741    public int getCustomInPlaceResId() {
742        return mCustomInPlaceResId;
743    }
744
745    /** @hide */
746    public Bitmap getThumbnail() {
747        return mThumbnail;
748    }
749
750    /** @hide */
751    public int getStartX() {
752        return mStartX;
753    }
754
755    /** @hide */
756    public int getStartY() {
757        return mStartY;
758    }
759
760    /** @hide */
761    public int getWidth() {
762        return mWidth;
763    }
764
765    /** @hide */
766    public int getHeight() {
767        return mHeight;
768    }
769
770    /** @hide */
771    public IRemoteCallback getOnAnimationStartListener() {
772        return mAnimationStartedListener;
773    }
774
775    /** @hide */
776    public int getExitCoordinatorKey() { return mExitCoordinatorIndex; }
777
778    /** @hide */
779    public void abort() {
780        if (mAnimationStartedListener != null) {
781            try {
782                mAnimationStartedListener.sendResult(null);
783            } catch (RemoteException e) {
784            }
785        }
786    }
787
788    /** @hide */
789    public boolean isReturning() {
790        return mIsReturning;
791    }
792
793    /** @hide */
794    public ArrayList<String> getSharedElementNames() {
795        return mSharedElementNames;
796    }
797
798    /** @hide */
799    public ResultReceiver getResultReceiver() { return mTransitionReceiver; }
800
801    /** @hide */
802    public int getResultCode() { return mResultCode; }
803
804    /** @hide */
805    public Intent getResultData() { return mResultData; }
806
807    /** @hide */
808    public PendingIntent getUsageTimeReport() {
809        return mUsageTimeReport;
810    }
811
812    /** @hide */
813    public static void abort(Bundle options) {
814        if (options != null) {
815            (new ActivityOptions(options)).abort();
816        }
817    }
818
819    /** @hide */
820    public int getDockCreateMode() { return mDockCreateMode; }
821
822    /** @hide */
823    public void setDockCreateMode(int dockCreateMode) {
824        mDockCreateMode = dockCreateMode;
825    }
826
827    /**
828     * Update the current values in this ActivityOptions from those supplied
829     * in <var>otherOptions</var>.  Any values
830     * defined in <var>otherOptions</var> replace those in the base options.
831     */
832    public void update(ActivityOptions otherOptions) {
833        if (otherOptions.mPackageName != null) {
834            mPackageName = otherOptions.mPackageName;
835        }
836        mUsageTimeReport = otherOptions.mUsageTimeReport;
837        mTransitionReceiver = null;
838        mSharedElementNames = null;
839        mIsReturning = false;
840        mResultData = null;
841        mResultCode = 0;
842        mExitCoordinatorIndex = 0;
843        mAnimationType = otherOptions.mAnimationType;
844        switch (otherOptions.mAnimationType) {
845            case ANIM_CUSTOM:
846                mCustomEnterResId = otherOptions.mCustomEnterResId;
847                mCustomExitResId = otherOptions.mCustomExitResId;
848                mThumbnail = null;
849                if (mAnimationStartedListener != null) {
850                    try {
851                        mAnimationStartedListener.sendResult(null);
852                    } catch (RemoteException e) {
853                    }
854                }
855                mAnimationStartedListener = otherOptions.mAnimationStartedListener;
856                break;
857            case ANIM_CUSTOM_IN_PLACE:
858                mCustomInPlaceResId = otherOptions.mCustomInPlaceResId;
859                break;
860            case ANIM_SCALE_UP:
861                mStartX = otherOptions.mStartX;
862                mStartY = otherOptions.mStartY;
863                mWidth = otherOptions.mWidth;
864                mHeight = otherOptions.mHeight;
865                if (mAnimationStartedListener != null) {
866                    try {
867                        mAnimationStartedListener.sendResult(null);
868                    } catch (RemoteException e) {
869                    }
870                }
871                mAnimationStartedListener = null;
872                break;
873            case ANIM_THUMBNAIL_SCALE_UP:
874            case ANIM_THUMBNAIL_SCALE_DOWN:
875            case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
876            case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
877                mThumbnail = otherOptions.mThumbnail;
878                mStartX = otherOptions.mStartX;
879                mStartY = otherOptions.mStartY;
880                mWidth = otherOptions.mWidth;
881                mHeight = otherOptions.mHeight;
882                if (mAnimationStartedListener != null) {
883                    try {
884                        mAnimationStartedListener.sendResult(null);
885                    } catch (RemoteException e) {
886                    }
887                }
888                mAnimationStartedListener = otherOptions.mAnimationStartedListener;
889                break;
890            case ANIM_SCENE_TRANSITION:
891                mTransitionReceiver = otherOptions.mTransitionReceiver;
892                mSharedElementNames = otherOptions.mSharedElementNames;
893                mIsReturning = otherOptions.mIsReturning;
894                mThumbnail = null;
895                mAnimationStartedListener = null;
896                mResultData = otherOptions.mResultData;
897                mResultCode = otherOptions.mResultCode;
898                mExitCoordinatorIndex = otherOptions.mExitCoordinatorIndex;
899                break;
900        }
901    }
902
903    /**
904     * Returns the created options as a Bundle, which can be passed to
905     * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
906     * Context.startActivity(Intent, Bundle)} and related methods.
907     * Note that the returned Bundle is still owned by the ActivityOptions
908     * object; you must not modify it, but can supply it to the startActivity
909     * methods that take an options Bundle.
910     */
911    public Bundle toBundle() {
912        if (mAnimationType == ANIM_DEFAULT) {
913            return null;
914        }
915        Bundle b = new Bundle();
916        if (mPackageName != null) {
917            b.putString(KEY_PACKAGE_NAME, mPackageName);
918        }
919        if (mHasBounds) {
920            b.putParcelable(KEY_BOUNDS, mBounds);
921        }
922        b.putInt(KEY_ANIM_TYPE, mAnimationType);
923        if (mUsageTimeReport != null) {
924            b.putParcelable(KEY_USAGE_TIME_REPORT, mUsageTimeReport);
925        }
926        switch (mAnimationType) {
927            case ANIM_CUSTOM:
928                b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
929                b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
930                b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
931                        != null ? mAnimationStartedListener.asBinder() : null);
932                break;
933            case ANIM_CUSTOM_IN_PLACE:
934                b.putInt(KEY_ANIM_IN_PLACE_RES_ID, mCustomInPlaceResId);
935                break;
936            case ANIM_SCALE_UP:
937            case ANIM_CLIP_REVEAL:
938                b.putInt(KEY_ANIM_START_X, mStartX);
939                b.putInt(KEY_ANIM_START_Y, mStartY);
940                b.putInt(KEY_ANIM_WIDTH, mWidth);
941                b.putInt(KEY_ANIM_HEIGHT, mHeight);
942                break;
943            case ANIM_THUMBNAIL_SCALE_UP:
944            case ANIM_THUMBNAIL_SCALE_DOWN:
945            case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
946            case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
947                b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
948                b.putInt(KEY_ANIM_START_X, mStartX);
949                b.putInt(KEY_ANIM_START_Y, mStartY);
950                b.putInt(KEY_ANIM_WIDTH, mWidth);
951                b.putInt(KEY_ANIM_HEIGHT, mHeight);
952                b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
953                        != null ? mAnimationStartedListener.asBinder() : null);
954                break;
955            case ANIM_SCENE_TRANSITION:
956                if (mTransitionReceiver != null) {
957                    b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mTransitionReceiver);
958                }
959                b.putBoolean(KEY_TRANSITION_IS_RETURNING, mIsReturning);
960                b.putStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS, mSharedElementNames);
961                b.putParcelable(KEY_RESULT_DATA, mResultData);
962                b.putInt(KEY_RESULT_CODE, mResultCode);
963                b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
964                break;
965        }
966        b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode);
967
968        return b;
969    }
970
971    /**
972     * Ask the the system track that time the user spends in the app being launched, and
973     * report it back once done.  The report will be sent to the given receiver, with
974     * the extras {@link #EXTRA_USAGE_TIME_REPORT} and {@link #EXTRA_USAGE_TIME_REPORT_PACKAGES}
975     * filled in.
976     *
977     * <p>The time interval tracked is from launching this activity until the user leaves
978     * that activity's flow.  They are considered to stay in the flow as long as
979     * new activities are being launched or returned to from the original flow,
980     * even if this crosses package or task boundaries.  For example, if the originator
981     * starts an activity to view an image, and while there the user selects to share,
982     * which launches their email app in a new task, and they complete the share, the
983     * time during that entire operation will be included until they finally hit back from
984     * the original image viewer activity.</p>
985     *
986     * <p>The user is considered to complete a flow once they switch to another
987     * activity that is not part of the tracked flow.  This may happen, for example, by
988     * using the notification shade, launcher, or recents to launch or switch to another
989     * app.  Simply going in to these navigation elements does not break the flow (although
990     * the launcher and recents stops time tracking of the session); it is the act of
991     * going somewhere else that completes the tracking.</p>
992     *
993     * @param receiver A broadcast receiver that willl receive the report.
994     */
995    public void requestUsageTimeReport(PendingIntent receiver) {
996        mUsageTimeReport = receiver;
997    }
998
999    /**
1000     * Return the filtered options only meant to be seen by the target activity itself
1001     * @hide
1002     */
1003    public ActivityOptions forTargetActivity() {
1004        if (mAnimationType == ANIM_SCENE_TRANSITION) {
1005            final ActivityOptions result = new ActivityOptions();
1006            result.update(this);
1007            return result;
1008        }
1009
1010        return null;
1011    }
1012
1013}
1014