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