ActivityOptions.java revision caa03107d4322b0e30f92e6dc1eb1ea73b1bf747
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.graphics.Bitmap;
21import android.os.Bundle;
22import android.os.Handler;
23import android.os.IRemoteCallback;
24import android.os.RemoteException;
25import android.os.ResultReceiver;
26import android.transition.Transition;
27import android.util.ArrayMap;
28import android.util.Pair;
29import android.view.View;
30import android.view.Window;
31
32import java.util.List;
33import java.util.Map;
34
35/**
36 * Helper class for building an options Bundle that can be used with
37 * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
38 * Context.startActivity(Intent, Bundle)} and related methods.
39 */
40public class ActivityOptions {
41    private static final String TAG = "ActivityOptions";
42
43    /**
44     * The package name that created the options.
45     * @hide
46     */
47    public static final String KEY_PACKAGE_NAME = "android:packageName";
48
49    /**
50     * Type of animation that arguments specify.
51     * @hide
52     */
53    public static final String KEY_ANIM_TYPE = "android:animType";
54
55    /**
56     * Custom enter animation resource ID.
57     * @hide
58     */
59    public static final String KEY_ANIM_ENTER_RES_ID = "android:animEnterRes";
60
61    /**
62     * Custom exit animation resource ID.
63     * @hide
64     */
65    public static final String KEY_ANIM_EXIT_RES_ID = "android:animExitRes";
66
67    /**
68     * Bitmap for thumbnail animation.
69     * @hide
70     */
71    public static final String KEY_ANIM_THUMBNAIL = "android:animThumbnail";
72
73    /**
74     * Start X position of thumbnail animation.
75     * @hide
76     */
77    public static final String KEY_ANIM_START_X = "android:animStartX";
78
79    /**
80     * Start Y position of thumbnail animation.
81     * @hide
82     */
83    public static final String KEY_ANIM_START_Y = "android:animStartY";
84
85    /**
86     * Initial width of the animation.
87     * @hide
88     */
89    public static final String KEY_ANIM_START_WIDTH = "android:animStartWidth";
90
91    /**
92     * Initial height of the animation.
93     * @hide
94     */
95    public static final String KEY_ANIM_START_HEIGHT = "android:animStartHeight";
96
97    /**
98     * Callback for when animation is started.
99     * @hide
100     */
101    public static final String KEY_ANIM_START_LISTENER = "android:animStartListener";
102
103    /**
104     * For Activity transitions, the calling Activity's TransitionListener used to
105     * notify the called Activity when the shared element and the exit transitions
106     * complete.
107     */
108    private static final String KEY_TRANSITION_COMPLETE_LISTENER
109            = "android:transitionCompleteListener";
110
111    /** @hide */
112    public static final int ANIM_NONE = 0;
113    /** @hide */
114    public static final int ANIM_CUSTOM = 1;
115    /** @hide */
116    public static final int ANIM_SCALE_UP = 2;
117    /** @hide */
118    public static final int ANIM_THUMBNAIL_SCALE_UP = 3;
119    /** @hide */
120    public static final int ANIM_THUMBNAIL_SCALE_DOWN = 4;
121    /** @hide */
122    public static final int ANIM_SCENE_TRANSITION = 5;
123
124    private String mPackageName;
125    private int mAnimationType = ANIM_NONE;
126    private int mCustomEnterResId;
127    private int mCustomExitResId;
128    private Bitmap mThumbnail;
129    private int mStartX;
130    private int mStartY;
131    private int mStartWidth;
132    private int mStartHeight;
133    private IRemoteCallback mAnimationStartedListener;
134    private ResultReceiver mExitReceiver;
135
136    /**
137     * Create an ActivityOptions specifying a custom animation to run when
138     * the activity is displayed.
139     *
140     * @param context Who is defining this.  This is the application that the
141     * animation resources will be loaded from.
142     * @param enterResId A resource ID of the animation resource to use for
143     * the incoming activity.  Use 0 for no animation.
144     * @param exitResId A resource ID of the animation resource to use for
145     * the outgoing activity.  Use 0 for no animation.
146     * @return Returns a new ActivityOptions object that you can use to
147     * supply these options as the options Bundle when starting an activity.
148     */
149    public static ActivityOptions makeCustomAnimation(Context context,
150            int enterResId, int exitResId) {
151        return makeCustomAnimation(context, enterResId, exitResId, null, null);
152    }
153
154    /**
155     * Create an ActivityOptions specifying a custom animation to run when
156     * the activity is displayed.
157     *
158     * @param context Who is defining this.  This is the application that the
159     * animation resources will be loaded from.
160     * @param enterResId A resource ID of the animation resource to use for
161     * the incoming activity.  Use 0 for no animation.
162     * @param exitResId A resource ID of the animation resource to use for
163     * the outgoing activity.  Use 0 for no animation.
164     * @param handler If <var>listener</var> is non-null this must be a valid
165     * Handler on which to dispatch the callback; otherwise it should be null.
166     * @param listener Optional OnAnimationStartedListener to find out when the
167     * requested animation has started running.  If for some reason the animation
168     * is not executed, the callback will happen immediately.
169     * @return Returns a new ActivityOptions object that you can use to
170     * supply these options as the options Bundle when starting an activity.
171     * @hide
172     */
173    public static ActivityOptions makeCustomAnimation(Context context,
174            int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener) {
175        ActivityOptions opts = new ActivityOptions();
176        opts.mPackageName = context.getPackageName();
177        opts.mAnimationType = ANIM_CUSTOM;
178        opts.mCustomEnterResId = enterResId;
179        opts.mCustomExitResId = exitResId;
180        opts.setOnAnimationStartedListener(handler, listener);
181        return opts;
182    }
183
184    private void setOnAnimationStartedListener(Handler handler,
185            OnAnimationStartedListener listener) {
186        if (listener != null) {
187            final Handler h = handler;
188            final OnAnimationStartedListener finalListener = listener;
189            mAnimationStartedListener = new IRemoteCallback.Stub() {
190                @Override public void sendResult(Bundle data) throws RemoteException {
191                    h.post(new Runnable() {
192                        @Override public void run() {
193                            finalListener.onAnimationStarted();
194                        }
195                    });
196                }
197            };
198        }
199    }
200
201    /**
202     * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
203     * to find out when the given animation has started running.
204     * @hide
205     */
206    public interface OnAnimationStartedListener {
207        void onAnimationStarted();
208    }
209
210    /**
211     * Create an ActivityOptions specifying an animation where the new
212     * activity is scaled from a small originating area of the screen to
213     * its final full representation.
214     *
215     * <p>If the Intent this is being used with has not set its
216     * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
217     * those bounds will be filled in for you based on the initial
218     * bounds passed in here.
219     *
220     * @param source The View that the new activity is animating from.  This
221     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
222     * @param startX The x starting location of the new activity, relative to <var>source</var>.
223     * @param startY The y starting location of the activity, relative to <var>source</var>.
224     * @param startWidth The initial width of the new activity.
225     * @param startHeight The initial height of the new activity.
226     * @return Returns a new ActivityOptions object that you can use to
227     * supply these options as the options Bundle when starting an activity.
228     */
229    public static ActivityOptions makeScaleUpAnimation(View source,
230            int startX, int startY, int startWidth, int startHeight) {
231        ActivityOptions opts = new ActivityOptions();
232        opts.mPackageName = source.getContext().getPackageName();
233        opts.mAnimationType = ANIM_SCALE_UP;
234        int[] pts = new int[2];
235        source.getLocationOnScreen(pts);
236        opts.mStartX = pts[0] + startX;
237        opts.mStartY = pts[1] + startY;
238        opts.mStartWidth = startWidth;
239        opts.mStartHeight = startHeight;
240        return opts;
241    }
242
243    /**
244     * Create an ActivityOptions specifying an animation where a thumbnail
245     * is scaled from a given position to the new activity window that is
246     * being started.
247     *
248     * <p>If the Intent this is being used with has not set its
249     * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
250     * those bounds will be filled in for you based on the initial
251     * thumbnail location and size provided here.
252     *
253     * @param source The View that this thumbnail is animating from.  This
254     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
255     * @param thumbnail The bitmap that will be shown as the initial thumbnail
256     * of the animation.
257     * @param startX The x starting location of the bitmap, relative to <var>source</var>.
258     * @param startY The y starting location of the bitmap, relative to <var>source</var>.
259     * @return Returns a new ActivityOptions object that you can use to
260     * supply these options as the options Bundle when starting an activity.
261     */
262    public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
263            Bitmap thumbnail, int startX, int startY) {
264        return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, null);
265    }
266
267    /**
268     * Create an ActivityOptions specifying an animation where a thumbnail
269     * is scaled from a given position to the new activity window that is
270     * being started.
271     *
272     * @param source The View that this thumbnail is animating from.  This
273     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
274     * @param thumbnail The bitmap that will be shown as the initial thumbnail
275     * of the animation.
276     * @param startX The x starting location of the bitmap, relative to <var>source</var>.
277     * @param startY The y starting location of the bitmap, relative to <var>source</var>.
278     * @param listener Optional OnAnimationStartedListener to find out when the
279     * requested animation has started running.  If for some reason the animation
280     * is not executed, the callback will happen immediately.
281     * @return Returns a new ActivityOptions object that you can use to
282     * supply these options as the options Bundle when starting an activity.
283     * @hide
284     */
285    public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
286            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
287        return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true);
288    }
289
290    /**
291     * Create an ActivityOptions specifying an animation where an activity window
292     * is scaled from a given position to a thumbnail at a specified location.
293     *
294     * @param source The View that this thumbnail is animating to.  This
295     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
296     * @param thumbnail The bitmap that will be shown as the final thumbnail
297     * of the animation.
298     * @param startX The x end location of the bitmap, relative to <var>source</var>.
299     * @param startY The y end location of the bitmap, relative to <var>source</var>.
300     * @param listener Optional OnAnimationStartedListener to find out when the
301     * requested animation has started running.  If for some reason the animation
302     * is not executed, the callback will happen immediately.
303     * @return Returns a new ActivityOptions object that you can use to
304     * supply these options as the options Bundle when starting an activity.
305     * @hide
306     */
307    public static ActivityOptions makeThumbnailScaleDownAnimation(View source,
308            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
309        return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, false);
310    }
311
312    private static ActivityOptions makeThumbnailAnimation(View source,
313            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
314            boolean scaleUp) {
315        ActivityOptions opts = new ActivityOptions();
316        opts.mPackageName = source.getContext().getPackageName();
317        opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN;
318        opts.mThumbnail = thumbnail;
319        int[] pts = new int[2];
320        source.getLocationOnScreen(pts);
321        opts.mStartX = pts[0] + startX;
322        opts.mStartY = pts[1] + startY;
323        opts.setOnAnimationStartedListener(source.getHandler(), listener);
324        return opts;
325    }
326
327    /**
328     * Create an ActivityOptions to transition between Activities using cross-Activity scene
329     * animations. This method carries the position of one shared element to the started Activity.
330     * The position of <code>sharedElement</code> will be used as the epicenter for the
331     * exit Transition. The position of the shared element in the launched Activity will be the
332     * epicenter of its entering Transition.
333     *
334     * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
335     * enabled on the calling Activity to cause an exit transition. The same must be in
336     * the called Activity to get an entering transition.</p>
337     * @param window The window containing shared elements.
338     * @param sharedElement The View to transition to the started Activity. sharedElement must
339     *                      have a non-null sharedElementName.
340     * @param sharedElementName The shared element name as used in the target Activity. This may
341     *                          be null if it has the same name as sharedElement.
342     * @return Returns a new ActivityOptions object that you can use to
343     *         supply these options as the options Bundle when starting an activity.
344     * @see android.transition.Transition#setEpicenterCallback(
345     *          android.transition.Transition.EpicenterCallback)
346     */
347    public static ActivityOptions makeSceneTransitionAnimation(Window window,
348            View sharedElement, String sharedElementName) {
349        return makeSceneTransitionAnimation(window,
350                new SharedElementMappingListener(sharedElement, sharedElementName));
351    }
352
353    /**
354     * Create an ActivityOptions to transition between Activities using cross-Activity scene
355     * animations. This method carries the position of multiple shared elements to the started
356     * Activity. The position of the first element in the value returned from
357     * {@link android.app.ActivityOptions.ActivityTransitionListener#getSharedElementsMapping()}
358     * will be used as the epicenter for the exit Transition. The position of the associated
359     * shared element in the launched Activity will be the epicenter of its entering Transition.
360     *
361     * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
362     * enabled on the calling Activity to cause an exit transition. The same must be in
363     * the called Activity to get an entering transition.</p>
364     * @param window The window containing shared elements.
365     * @param listener The listener to use to monitor activity transition events.
366     * @return Returns a new ActivityOptions object that you can use to
367     *         supply these options as the options Bundle when starting an activity.
368     * @see android.transition.Transition#setEpicenterCallback(
369     *          android.transition.Transition.EpicenterCallback)
370     */
371    public static ActivityOptions makeSceneTransitionAnimation(Window window,
372            ActivityTransitionListener listener) {
373        ActivityOptions opts = new ActivityOptions();
374        opts.mAnimationType = ANIM_SCENE_TRANSITION;
375        ExitTransitionCoordinator exit = new ExitTransitionCoordinator(window, listener);
376        opts.mExitReceiver = exit;
377        return opts;
378    }
379
380    private ActivityOptions() {
381    }
382
383    /** @hide */
384    public ActivityOptions(Bundle opts) {
385        mPackageName = opts.getString(KEY_PACKAGE_NAME);
386        mAnimationType = opts.getInt(KEY_ANIM_TYPE);
387        switch (mAnimationType) {
388            case ANIM_CUSTOM:
389                mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
390                mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
391                mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
392                        opts.getBinder(KEY_ANIM_START_LISTENER));
393                break;
394
395            case ANIM_SCALE_UP:
396                mStartX = opts.getInt(KEY_ANIM_START_X, 0);
397                mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
398                mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0);
399                mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0);
400                break;
401
402            case ANIM_THUMBNAIL_SCALE_UP:
403            case ANIM_THUMBNAIL_SCALE_DOWN:
404                mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL);
405                mStartX = opts.getInt(KEY_ANIM_START_X, 0);
406                mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
407                mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
408                        opts.getBinder(KEY_ANIM_START_LISTENER));
409                break;
410
411            case ANIM_SCENE_TRANSITION:
412                mExitReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
413                break;
414        }
415    }
416
417    /** @hide */
418    public String getPackageName() {
419        return mPackageName;
420    }
421
422    /** @hide */
423    public int getAnimationType() {
424        return mAnimationType;
425    }
426
427    /** @hide */
428    public int getCustomEnterResId() {
429        return mCustomEnterResId;
430    }
431
432    /** @hide */
433    public int getCustomExitResId() {
434        return mCustomExitResId;
435    }
436
437    /** @hide */
438    public Bitmap getThumbnail() {
439        return mThumbnail;
440    }
441
442    /** @hide */
443    public int getStartX() {
444        return mStartX;
445    }
446
447    /** @hide */
448    public int getStartY() {
449        return mStartY;
450    }
451
452    /** @hide */
453    public int getStartWidth() {
454        return mStartWidth;
455    }
456
457    /** @hide */
458    public int getStartHeight() {
459        return mStartHeight;
460    }
461
462    /** @hide */
463    public IRemoteCallback getOnAnimationStartListener() {
464        return mAnimationStartedListener;
465    }
466
467    /** @hide */
468    public void dispatchActivityStopped() {
469        if (mExitReceiver != null) {
470            mExitReceiver.send(ActivityTransitionCoordinator.MSG_ACTIVITY_STOPPED, null);
471        }
472    }
473
474    /** @hide */
475    public void dispatchStartExit() {
476        if (mExitReceiver != null) {
477            mExitReceiver.send(ActivityTransitionCoordinator.MSG_START_EXIT_TRANSITION, null);
478        }
479    }
480
481    /** @hide */
482    public void abort() {
483        if (mAnimationStartedListener != null) {
484            try {
485                mAnimationStartedListener.sendResult(null);
486            } catch (RemoteException e) {
487            }
488        }
489    }
490
491    /** @hide */
492    public static void abort(Bundle options) {
493        if (options != null) {
494            (new ActivityOptions(options)).abort();
495        }
496    }
497
498    /** @hide */
499    public EnterTransitionCoordinator createEnterActivityTransition(Activity activity) {
500        EnterTransitionCoordinator coordinator = null;
501        if (mAnimationType == ANIM_SCENE_TRANSITION) {
502            coordinator = new EnterTransitionCoordinator(activity, mExitReceiver);
503        }
504        return coordinator;
505    }
506
507    /**
508     * Update the current values in this ActivityOptions from those supplied
509     * in <var>otherOptions</var>.  Any values
510     * defined in <var>otherOptions</var> replace those in the base options.
511     */
512    public void update(ActivityOptions otherOptions) {
513        if (otherOptions.mPackageName != null) {
514            mPackageName = otherOptions.mPackageName;
515        }
516        mExitReceiver = null;
517        switch (otherOptions.mAnimationType) {
518            case ANIM_CUSTOM:
519                mAnimationType = otherOptions.mAnimationType;
520                mCustomEnterResId = otherOptions.mCustomEnterResId;
521                mCustomExitResId = otherOptions.mCustomExitResId;
522                mThumbnail = null;
523                if (mAnimationStartedListener != null) {
524                    try {
525                        mAnimationStartedListener.sendResult(null);
526                    } catch (RemoteException e) {
527                    }
528                }
529                mAnimationStartedListener = otherOptions.mAnimationStartedListener;
530                break;
531            case ANIM_SCALE_UP:
532                mAnimationType = otherOptions.mAnimationType;
533                mStartX = otherOptions.mStartX;
534                mStartY = otherOptions.mStartY;
535                mStartWidth = otherOptions.mStartWidth;
536                mStartHeight = otherOptions.mStartHeight;
537                if (mAnimationStartedListener != null) {
538                    try {
539                        mAnimationStartedListener.sendResult(null);
540                    } catch (RemoteException e) {
541                    }
542                }
543                mAnimationStartedListener = null;
544                break;
545            case ANIM_THUMBNAIL_SCALE_UP:
546            case ANIM_THUMBNAIL_SCALE_DOWN:
547                mAnimationType = otherOptions.mAnimationType;
548                mThumbnail = otherOptions.mThumbnail;
549                mStartX = otherOptions.mStartX;
550                mStartY = otherOptions.mStartY;
551                if (mAnimationStartedListener != null) {
552                    try {
553                        mAnimationStartedListener.sendResult(null);
554                    } catch (RemoteException e) {
555                    }
556                }
557                mAnimationStartedListener = otherOptions.mAnimationStartedListener;
558                break;
559            case ANIM_SCENE_TRANSITION:
560                mAnimationType = otherOptions.mAnimationType;
561                mExitReceiver = otherOptions.mExitReceiver;
562                mThumbnail = null;
563                mAnimationStartedListener = null;
564                break;
565        }
566    }
567
568    /**
569     * Returns the created options as a Bundle, which can be passed to
570     * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
571     * Context.startActivity(Intent, Bundle)} and related methods.
572     * Note that the returned Bundle is still owned by the ActivityOptions
573     * object; you must not modify it, but can supply it to the startActivity
574     * methods that take an options Bundle.
575     */
576    public Bundle toBundle() {
577        Bundle b = new Bundle();
578        if (mPackageName != null) {
579            b.putString(KEY_PACKAGE_NAME, mPackageName);
580        }
581        switch (mAnimationType) {
582            case ANIM_CUSTOM:
583                b.putInt(KEY_ANIM_TYPE, mAnimationType);
584                b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
585                b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
586                b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
587                        != null ? mAnimationStartedListener.asBinder() : null);
588                break;
589            case ANIM_SCALE_UP:
590                b.putInt(KEY_ANIM_TYPE, mAnimationType);
591                b.putInt(KEY_ANIM_START_X, mStartX);
592                b.putInt(KEY_ANIM_START_Y, mStartY);
593                b.putInt(KEY_ANIM_START_WIDTH, mStartWidth);
594                b.putInt(KEY_ANIM_START_HEIGHT, mStartHeight);
595                break;
596            case ANIM_THUMBNAIL_SCALE_UP:
597            case ANIM_THUMBNAIL_SCALE_DOWN:
598                b.putInt(KEY_ANIM_TYPE, mAnimationType);
599                b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
600                b.putInt(KEY_ANIM_START_X, mStartX);
601                b.putInt(KEY_ANIM_START_Y, mStartY);
602                b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
603                        != null ? mAnimationStartedListener.asBinder() : null);
604                break;
605            case ANIM_SCENE_TRANSITION:
606                b.putInt(KEY_ANIM_TYPE, mAnimationType);
607                if (mExitReceiver != null) {
608                    b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mExitReceiver);
609                }
610                break;
611        }
612        return b;
613    }
614
615    /**
616     * Return the filtered options only meant to be seen by the target activity itself
617     * @hide
618     */
619    public ActivityOptions forTargetActivity() {
620        if (mAnimationType == ANIM_SCENE_TRANSITION) {
621            final ActivityOptions result = new ActivityOptions();
622            result.update(this);
623            return result;
624        }
625
626        return null;
627    }
628
629    /**
630     * Listener provided in
631     * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
632     * android.app.ActivityOptions.ActivityTransitionListener)} or in
633     * {@link android.app.Activity#setActivityTransitionListener(
634     * android.app.ActivityOptions.ActivityTransitionListener)} to monitor the Activity transitions.
635     * The events can be used to customize or override Activity Transition behavior.
636     */
637    public static class ActivityTransitionListener {
638        /**
639         * Called when the enter Transition is ready to start, but hasn't started yet. If
640         * {@link android.view.Window#getEnterTransition()} is non-null,
641         * The entering views will be {@link View#INVISIBLE}.
642         */
643        public void onEnterReady() {}
644
645        /**
646         * Called when the remote exiting transition completes.
647         */
648        public void onRemoteExitComplete() {}
649
650        /**
651         * Called when the start state for shared elements is captured on enter.
652         *
653         * @param sharedElementNames The names of the shared elements that were accepted into
654         *                           the View hierarchy.
655         * @param sharedElements The shared elements that are part of the View hierarchy.
656         * @param sharedElementSnapshots The Views containing snap shots of the shared element
657         *                               from the launching Window. These elements will not
658         *                               be part of the scene, but will be positioned relative
659         *                               to the Window decor View.
660         */
661        public void onCaptureSharedElementStart(List<String> sharedElementNames,
662                List<View> sharedElements, List<View> sharedElementSnapshots) {}
663
664        /**
665         * Called when the end state for shared elements is captured on enter.
666         *
667         * @param sharedElementNames The names of the shared elements that were accepted into
668         *                           the View hierarchy.
669         * @param sharedElements The shared elements that are part of the View hierarchy.
670         * @param sharedElementSnapshots The Views containing snap shots of the shared element
671         *                               from the launching Window. These elements will not
672         *                               be part of the scene, but will be positioned relative
673         *                               to the Window decor View.
674         */
675        public void onCaptureSharedElementEnd(List<String> sharedElementNames,
676                List<View> sharedElements, List<View> sharedElementSnapshots) {}
677
678        /**
679         * Called when the enter Transition has been started.
680         * @param sharedElementNames The names of shared elements that were transferred.
681         * @param sharedElements The shared elements that were transferred.
682         */
683        public void onStartEnterTransition(List<String> sharedElementNames,
684                List<View> sharedElements) {}
685
686        /**
687         * Called when the exit Transition has been started.
688         * @param sharedElementNames The names of all shared elements that will be transferred.
689         * @param sharedElements All shared elements that will be transferred.
690         */
691        public void onStartExitTransition(List<String> sharedElementNames,
692                List<View> sharedElements) {}
693
694        /**
695         * Called when the exiting shared element transition completes.
696         */
697        public void onSharedElementExitTransitionComplete() {}
698
699        /**
700         * Called on exit when the shared element has been transferred.
701         * @param sharedElementNames The names of all shared elements that were transferred.
702         * @param sharedElements All shared elements that will were transferred.
703         */
704        public void onSharedElementTransferred(List<String> sharedElementNames,
705                List<View> sharedElements) {}
706
707        /**
708         * Called when the exit transition has completed.
709         */
710        public void onExitTransitionComplete() {}
711
712        /**
713         * Returns a mapping from a View in the View hierarchy to the shared element name used
714         * in the call. This is called twice -- once when the view is
715         * entering and again when it exits. A null return value indicates that the
716         * View hierachy can be trusted without any remapping.
717         * @return A map from a View in the hierarchy to the shared element name used in the
718         * call.
719         */
720        public Pair<View, String>[] getSharedElementsMapping() { return null; }
721
722        /**
723         * Returns <code>true</code> if the ActivityTransitionListener will handle removing
724         * rejected shared elements from the scene. If <code>false</code> is returned, a default
725         * animation will be used to remove the rejected shared elements from the scene.
726         *
727         * @param rejectedSharedElements Views containing visual information of shared elements
728         *                               that are not part of the entering scene. These Views
729         *                               are positioned relative to the Window decor View.
730         * @return <code>false</code> if the default animation should be used to remove the
731         * rejected shared elements from the scene or <code>true</code> if the listener provides
732         * custom handling.
733         */
734        public boolean handleRejectedSharedElements(List<View> rejectedSharedElements) {
735            return false;
736        }
737    }
738
739    private static class SharedElementMappingListener extends ActivityTransitionListener {
740        Pair<View, String>[] mSharedElementsMapping = new Pair[1];
741
742        public SharedElementMappingListener(View view, String name) {
743            mSharedElementsMapping[0] = Pair.create(view, name);
744        }
745
746        @Override
747        public Pair<View, String>[] getSharedElementsMapping() {
748            return mSharedElementsMapping;
749        }
750    }
751}
752