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