ActivityOptions.java revision 18e905f42d017c4721d33bd25d7d39ef8d64b5d5
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.view.View;
26
27/**
28 * Helper class for building an options Bundle that can be used with
29 * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
30 * Context.startActivity(Intent, Bundle)} and related methods.
31 */
32public class ActivityOptions {
33    /**
34     * The package name that created the options.
35     * @hide
36     */
37    public static final String KEY_PACKAGE_NAME = "android:packageName";
38
39    /**
40     * Type of animation that arguments specify.
41     * @hide
42     */
43    public static final String KEY_ANIM_TYPE = "android:animType";
44
45    /**
46     * Custom enter animation resource ID.
47     * @hide
48     */
49    public static final String KEY_ANIM_ENTER_RES_ID = "android:animEnterRes";
50
51    /**
52     * Custom exit animation resource ID.
53     * @hide
54     */
55    public static final String KEY_ANIM_EXIT_RES_ID = "android:animExitRes";
56
57    /**
58     * Bitmap for thumbnail animation.
59     * @hide
60     */
61    public static final String KEY_ANIM_THUMBNAIL = "android:animThumbnail";
62
63    /**
64     * Start X position of thumbnail animation.
65     * @hide
66     */
67    public static final String KEY_ANIM_START_X = "android:animStartX";
68
69    /**
70     * Start Y position of thumbnail animation.
71     * @hide
72     */
73    public static final String KEY_ANIM_START_Y = "android:animStartY";
74
75    /**
76     * Initial width of the animation.
77     * @hide
78     */
79    public static final String KEY_ANIM_START_WIDTH = "android:animStartWidth";
80
81    /**
82     * Initial height of the animation.
83     * @hide
84     */
85    public static final String KEY_ANIM_START_HEIGHT = "android:animStartHeight";
86
87    /**
88     * Callback for when animation is started.
89     * @hide
90     */
91    public static final String KEY_ANIM_START_LISTENER = "android:animStartListener";
92
93    /**
94     * A string array of names for the destination scene. This defines an API in the same
95     * way that intent action or extra names do and should follow a similar convention:
96     * "com.example.scene.FOO"
97     *
98     * @hide
99     */
100    public static final String KEY_DEST_SCENE_NAMES = "android:destSceneNames";
101
102    /**
103     * A string indicating the destination scene name that was chosen by the target.
104     * Used by {@link OnSceneTransitionStartedListener}.
105     * @hide
106     */
107    public static final String KEY_DEST_SCENE_NAME_CHOSEN = "android:destSceneNameChosen";
108
109    /**
110     * Callback for when scene transition is started.
111     * @hide
112     */
113    public static final String KEY_SCENE_TRANSITION_START_LISTENER =
114            "android:sceneTransitionStartListener";
115
116    /**
117     * Arguments for the scene transition about to begin.
118     * @hide
119     */
120    public static final String KEY_SCENE_TRANSITION_ARGS = "android:sceneTransitionArgs";
121
122    /** @hide */
123    public static final int ANIM_NONE = 0;
124    /** @hide */
125    public static final int ANIM_CUSTOM = 1;
126    /** @hide */
127    public static final int ANIM_SCALE_UP = 2;
128    /** @hide */
129    public static final int ANIM_THUMBNAIL_SCALE_UP = 3;
130    /** @hide */
131    public static final int ANIM_THUMBNAIL_SCALE_DOWN = 4;
132    /** @hide */
133    public static final int ANIM_SCENE_TRANSITION = 5;
134
135    private String mPackageName;
136    private int mAnimationType = ANIM_NONE;
137    private int mCustomEnterResId;
138    private int mCustomExitResId;
139    private Bitmap mThumbnail;
140    private int mStartX;
141    private int mStartY;
142    private int mStartWidth;
143    private int mStartHeight;
144    private String[] mDestSceneNames;
145    private Bundle mTransitionArgs;
146    private IRemoteCallback mAnimationStartedListener;
147    private IRemoteCallback mSceneTransitionStartedListener;
148
149    /**
150     * Create an ActivityOptions specifying a custom animation to run when
151     * the activity is displayed.
152     *
153     * @param context Who is defining this.  This is the application that the
154     * animation resources will be loaded from.
155     * @param enterResId A resource ID of the animation resource to use for
156     * the incoming activity.  Use 0 for no animation.
157     * @param exitResId A resource ID of the animation resource to use for
158     * the outgoing activity.  Use 0 for no animation.
159     * @return Returns a new ActivityOptions object that you can use to
160     * supply these options as the options Bundle when starting an activity.
161     */
162    public static ActivityOptions makeCustomAnimation(Context context,
163            int enterResId, int exitResId) {
164        return makeCustomAnimation(context, enterResId, exitResId, null, null);
165    }
166
167    /**
168     * Create an ActivityOptions specifying a custom animation to run when
169     * the activity is displayed.
170     *
171     * @param context Who is defining this.  This is the application that the
172     * animation resources will be loaded from.
173     * @param enterResId A resource ID of the animation resource to use for
174     * the incoming activity.  Use 0 for no animation.
175     * @param exitResId A resource ID of the animation resource to use for
176     * the outgoing activity.  Use 0 for no animation.
177     * @param handler If <var>listener</var> is non-null this must be a valid
178     * Handler on which to dispatch the callback; otherwise it should be null.
179     * @param listener Optional OnAnimationStartedListener to find out when the
180     * requested animation has started running.  If for some reason the animation
181     * is not executed, the callback will happen immediately.
182     * @return Returns a new ActivityOptions object that you can use to
183     * supply these options as the options Bundle when starting an activity.
184     * @hide
185     */
186    public static ActivityOptions makeCustomAnimation(Context context,
187            int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener) {
188        ActivityOptions opts = new ActivityOptions();
189        opts.mPackageName = context.getPackageName();
190        opts.mAnimationType = ANIM_CUSTOM;
191        opts.mCustomEnterResId = enterResId;
192        opts.mCustomExitResId = exitResId;
193        opts.setOnAnimationStartedListener(handler, listener);
194        return opts;
195    }
196
197    private void setOnAnimationStartedListener(Handler handler,
198            OnAnimationStartedListener listener) {
199        if (listener != null) {
200            final Handler h = handler;
201            final OnAnimationStartedListener finalListener = listener;
202            mAnimationStartedListener = new IRemoteCallback.Stub() {
203                @Override public void sendResult(Bundle data) throws RemoteException {
204                    h.post(new Runnable() {
205                        @Override public void run() {
206                            finalListener.onAnimationStarted();
207                        }
208                    });
209                }
210            };
211        }
212    }
213
214    private void setOnSceneTransitionStartedListener(Handler handler,
215            OnSceneTransitionStartedListener listener) {
216        if (listener != null) {
217            final Handler h = handler;
218            final OnSceneTransitionStartedListener l = listener;
219            mSceneTransitionStartedListener = new IRemoteCallback.Stub() {
220                @Override public void sendResult(final Bundle data) throws RemoteException {
221                    h.post(new Runnable() {
222                        public void run() {
223                            l.onSceneTransitionStarted(data != null ?
224                                    data.getString(KEY_DEST_SCENE_NAME_CHOSEN) : null);
225                        }
226                    });
227                }
228            };
229        }
230    }
231
232    /**
233     * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
234     * to find out when the given animation has started running.
235     * @hide
236     */
237    public interface OnAnimationStartedListener {
238        void onAnimationStarted();
239    }
240
241    /**
242     * Callback for use with {@link ActivityOptions#makeSceneTransitionAnimation}
243     * to find out when a transition is about to begin.
244     * @hide
245     */
246    public interface OnSceneTransitionStartedListener {
247        void onSceneTransitionStarted(String destSceneName);
248    }
249
250    /**
251     * Create an ActivityOptions specifying an animation where the new
252     * activity is scaled from a small originating area of the screen to
253     * its final full representation.
254     *
255     * <p>If the Intent this is being used with has not set its
256     * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
257     * those bounds will be filled in for you based on the initial
258     * bounds passed in here.
259     *
260     * @param source The View that the new activity is animating from.  This
261     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
262     * @param startX The x starting location of the new activity, relative to <var>source</var>.
263     * @param startY The y starting location of the activity, relative to <var>source</var>.
264     * @param startWidth The initial width of the new activity.
265     * @param startHeight The initial height of the new activity.
266     * @return Returns a new ActivityOptions object that you can use to
267     * supply these options as the options Bundle when starting an activity.
268     */
269    public static ActivityOptions makeScaleUpAnimation(View source,
270            int startX, int startY, int startWidth, int startHeight) {
271        ActivityOptions opts = new ActivityOptions();
272        opts.mPackageName = source.getContext().getPackageName();
273        opts.mAnimationType = ANIM_SCALE_UP;
274        int[] pts = new int[2];
275        source.getLocationOnScreen(pts);
276        opts.mStartX = pts[0] + startX;
277        opts.mStartY = pts[1] + startY;
278        opts.mStartWidth = startWidth;
279        opts.mStartHeight = startHeight;
280        return opts;
281    }
282
283    /**
284     * Create an ActivityOptions specifying an animation where a thumbnail
285     * is scaled from a given position to the new activity window that is
286     * being started.
287     *
288     * <p>If the Intent this is being used with has not set its
289     * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
290     * those bounds will be filled in for you based on the initial
291     * thumbnail location and size provided here.
292     *
293     * @param source The View that this thumbnail is animating from.  This
294     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
295     * @param thumbnail The bitmap that will be shown as the initial thumbnail
296     * of the animation.
297     * @param startX The x starting location of the bitmap, relative to <var>source</var>.
298     * @param startY The y starting location of the bitmap, relative to <var>source</var>.
299     * @return Returns a new ActivityOptions object that you can use to
300     * supply these options as the options Bundle when starting an activity.
301     */
302    public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
303            Bitmap thumbnail, int startX, int startY) {
304        return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, null);
305    }
306
307    /**
308     * Create an ActivityOptions specifying an animation where a thumbnail
309     * is scaled from a given position to the new activity window that is
310     * being started.
311     *
312     * @param source The View that this thumbnail is animating from.  This
313     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
314     * @param thumbnail The bitmap that will be shown as the initial thumbnail
315     * of the animation.
316     * @param startX The x starting location of the bitmap, relative to <var>source</var>.
317     * @param startY The y starting location of the bitmap, relative to <var>source</var>.
318     * @param listener Optional OnAnimationStartedListener to find out when the
319     * requested animation has started running.  If for some reason the animation
320     * is not executed, the callback will happen immediately.
321     * @return Returns a new ActivityOptions object that you can use to
322     * supply these options as the options Bundle when starting an activity.
323     * @hide
324     */
325    public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
326            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
327        return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true);
328    }
329
330    /**
331     * Create an ActivityOptions specifying an animation where an activity window
332     * is scaled from a given position to a thumbnail at a specified location.
333     *
334     * @param source The View that this thumbnail is animating to.  This
335     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
336     * @param thumbnail The bitmap that will be shown as the final thumbnail
337     * of the animation.
338     * @param startX The x end location of the bitmap, relative to <var>source</var>.
339     * @param startY The y end location of the bitmap, relative to <var>source</var>.
340     * @param listener Optional OnAnimationStartedListener to find out when the
341     * requested animation has started running.  If for some reason the animation
342     * is not executed, the callback will happen immediately.
343     * @return Returns a new ActivityOptions object that you can use to
344     * supply these options as the options Bundle when starting an activity.
345     * @hide
346     */
347    public static ActivityOptions makeThumbnailScaleDownAnimation(View source,
348            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
349        return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, false);
350    }
351
352    private static ActivityOptions makeThumbnailAnimation(View source,
353            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
354            boolean scaleUp) {
355        ActivityOptions opts = new ActivityOptions();
356        opts.mPackageName = source.getContext().getPackageName();
357        opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN;
358        opts.mThumbnail = thumbnail;
359        int[] pts = new int[2];
360        source.getLocationOnScreen(pts);
361        opts.mStartX = pts[0] + startX;
362        opts.mStartY = pts[1] + startY;
363        opts.setOnAnimationStartedListener(source.getHandler(), listener);
364        return opts;
365    }
366
367    /**
368     * Create an ActivityOptions specifying an animation where an activity window is asked
369     * to perform animations within the window content.
370     *
371     * @hide
372     */
373    public static ActivityOptions makeSceneTransitionAnimation(String[] destSceneNames,
374            Bundle args, OnSceneTransitionStartedListener listener, Handler handler) {
375        ActivityOptions opts = new ActivityOptions();
376        opts.mAnimationType = ANIM_SCENE_TRANSITION;
377        opts.mDestSceneNames = destSceneNames;
378        opts.mTransitionArgs = args;
379        opts.setOnSceneTransitionStartedListener(handler, listener);
380        return opts;
381    }
382
383    private ActivityOptions() {
384    }
385
386    /** @hide */
387    public ActivityOptions(Bundle opts) {
388        mPackageName = opts.getString(KEY_PACKAGE_NAME);
389        mAnimationType = opts.getInt(KEY_ANIM_TYPE);
390        switch (mAnimationType) {
391            case ANIM_CUSTOM:
392                mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
393                mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
394                mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
395                        opts.getBinder(KEY_ANIM_START_LISTENER));
396                break;
397
398            case ANIM_SCALE_UP:
399                mStartX = opts.getInt(KEY_ANIM_START_X, 0);
400                mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
401                mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0);
402                mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0);
403                break;
404
405            case ANIM_THUMBNAIL_SCALE_UP:
406            case ANIM_THUMBNAIL_SCALE_DOWN:
407                mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL);
408                mStartX = opts.getInt(KEY_ANIM_START_X, 0);
409                mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
410                mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
411                        opts.getBinder(KEY_ANIM_START_LISTENER));
412                break;
413
414            case ANIM_SCENE_TRANSITION:
415                mDestSceneNames = opts.getStringArray(KEY_DEST_SCENE_NAMES);
416                mTransitionArgs = opts.getBundle(KEY_SCENE_TRANSITION_ARGS);
417                mSceneTransitionStartedListener = IRemoteCallback.Stub.asInterface(
418                        opts.getBinder(KEY_SCENE_TRANSITION_START_LISTENER));
419                break;
420        }
421    }
422
423    /** @hide */
424    public String getPackageName() {
425        return mPackageName;
426    }
427
428    /** @hide */
429    public int getAnimationType() {
430        return mAnimationType;
431    }
432
433    /** @hide */
434    public int getCustomEnterResId() {
435        return mCustomEnterResId;
436    }
437
438    /** @hide */
439    public int getCustomExitResId() {
440        return mCustomExitResId;
441    }
442
443    /** @hide */
444    public Bitmap getThumbnail() {
445        return mThumbnail;
446    }
447
448    /** @hide */
449    public int getStartX() {
450        return mStartX;
451    }
452
453    /** @hide */
454    public int getStartY() {
455        return mStartY;
456    }
457
458    /** @hide */
459    public int getStartWidth() {
460        return mStartWidth;
461    }
462
463    /** @hide */
464    public int getStartHeight() {
465        return mStartHeight;
466    }
467
468    /** @hide */
469    public String[] getDestSceneNames() {
470        return mDestSceneNames;
471    }
472
473    /** @hide */
474    public Bundle getSceneTransitionArgs() {
475        return mTransitionArgs;
476    }
477
478    /** @hide */
479    public IRemoteCallback getOnAnimationStartListener() {
480        return mAnimationStartedListener;
481    }
482
483    /** @hide */
484    public IRemoteCallback getOnSceneTransitionStartedListener() {
485        return mSceneTransitionStartedListener;
486    }
487
488    /** @hide */
489    public void abort() {
490        if (mAnimationStartedListener != null) {
491            try {
492                mAnimationStartedListener.sendResult(null);
493            } catch (RemoteException e) {
494            }
495        }
496    }
497
498    /** @hide */
499    public static void abort(Bundle options) {
500        if (options != null) {
501            (new ActivityOptions(options)).abort();
502        }
503    }
504
505    /**
506     * Update the current values in this ActivityOptions from those supplied
507     * in <var>otherOptions</var>.  Any values
508     * defined in <var>otherOptions</var> replace those in the base options.
509     */
510    public void update(ActivityOptions otherOptions) {
511        if (otherOptions.mPackageName != null) {
512            mPackageName = otherOptions.mPackageName;
513        }
514        switch (otherOptions.mAnimationType) {
515            case ANIM_CUSTOM:
516                mAnimationType = otherOptions.mAnimationType;
517                mCustomEnterResId = otherOptions.mCustomEnterResId;
518                mCustomExitResId = otherOptions.mCustomExitResId;
519                mThumbnail = null;
520                if (mAnimationStartedListener != null) {
521                    try {
522                        mAnimationStartedListener.sendResult(null);
523                    } catch (RemoteException e) {
524                    }
525                }
526                mAnimationStartedListener = otherOptions.mAnimationStartedListener;
527                mSceneTransitionStartedListener = null;
528                mTransitionArgs = null;
529                mDestSceneNames = null;
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                mSceneTransitionStartedListener = null;
545                mTransitionArgs = null;
546                mDestSceneNames = null;
547                break;
548            case ANIM_THUMBNAIL_SCALE_UP:
549            case ANIM_THUMBNAIL_SCALE_DOWN:
550                mAnimationType = otherOptions.mAnimationType;
551                mThumbnail = otherOptions.mThumbnail;
552                mStartX = otherOptions.mStartX;
553                mStartY = otherOptions.mStartY;
554                if (mAnimationStartedListener != null) {
555                    try {
556                        mAnimationStartedListener.sendResult(null);
557                    } catch (RemoteException e) {
558                    }
559                }
560                mAnimationStartedListener = otherOptions.mAnimationStartedListener;
561                mSceneTransitionStartedListener = null;
562                mTransitionArgs = null;
563                mDestSceneNames = null;
564                break;
565            case ANIM_SCENE_TRANSITION:
566                mAnimationType = otherOptions.mAnimationType;
567                if (mSceneTransitionStartedListener != null) {
568                    try {
569                        mSceneTransitionStartedListener.sendResult(null);
570                    } catch (RemoteException e) {
571                    }
572                }
573                mSceneTransitionStartedListener = otherOptions.mSceneTransitionStartedListener;
574                mDestSceneNames = otherOptions.mDestSceneNames;
575                mAnimationStartedListener = null;
576                break;
577        }
578    }
579
580    /**
581     * Returns the created options as a Bundle, which can be passed to
582     * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
583     * Context.startActivity(Intent, Bundle)} and related methods.
584     * Note that the returned Bundle is still owned by the ActivityOptions
585     * object; you must not modify it, but can supply it to the startActivity
586     * methods that take an options Bundle.
587     */
588    public Bundle toBundle() {
589        Bundle b = new Bundle();
590        if (mPackageName != null) {
591            b.putString(KEY_PACKAGE_NAME, mPackageName);
592        }
593        switch (mAnimationType) {
594            case ANIM_CUSTOM:
595                b.putInt(KEY_ANIM_TYPE, mAnimationType);
596                b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
597                b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
598                b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
599                        != null ? mAnimationStartedListener.asBinder() : null);
600                break;
601            case ANIM_SCALE_UP:
602                b.putInt(KEY_ANIM_TYPE, mAnimationType);
603                b.putInt(KEY_ANIM_START_X, mStartX);
604                b.putInt(KEY_ANIM_START_Y, mStartY);
605                b.putInt(KEY_ANIM_START_WIDTH, mStartWidth);
606                b.putInt(KEY_ANIM_START_HEIGHT, mStartHeight);
607                break;
608            case ANIM_THUMBNAIL_SCALE_UP:
609            case ANIM_THUMBNAIL_SCALE_DOWN:
610                b.putInt(KEY_ANIM_TYPE, mAnimationType);
611                b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
612                b.putInt(KEY_ANIM_START_X, mStartX);
613                b.putInt(KEY_ANIM_START_Y, mStartY);
614                b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
615                        != null ? mAnimationStartedListener.asBinder() : null);
616                break;
617        }
618        return b;
619    }
620}
621