Home | History | Annotate | Download | only in app
      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.graphics.Bitmap;
     21 import android.os.Bundle;
     22 import android.os.Handler;
     23 import android.os.IRemoteCallback;
     24 import android.os.RemoteException;
     25 import 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  */
     32 public 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     /** @hide */
     94     public static final int ANIM_NONE = 0;
     95     /** @hide */
     96     public static final int ANIM_CUSTOM = 1;
     97     /** @hide */
     98     public static final int ANIM_SCALE_UP = 2;
     99     /** @hide */
    100     public static final int ANIM_THUMBNAIL = 3;
    101     /** @hide */
    102     public static final int ANIM_THUMBNAIL_DELAYED = 4;
    103 
    104     private String mPackageName;
    105     private int mAnimationType = ANIM_NONE;
    106     private int mCustomEnterResId;
    107     private int mCustomExitResId;
    108     private Bitmap mThumbnail;
    109     private int mStartX;
    110     private int mStartY;
    111     private int mStartWidth;
    112     private int mStartHeight;
    113     private IRemoteCallback mAnimationStartedListener;
    114 
    115     /**
    116      * Create an ActivityOptions specifying a custom animation to run when
    117      * the activity is displayed.
    118      *
    119      * @param context Who is defining this.  This is the application that the
    120      * animation resources will be loaded from.
    121      * @param enterResId A resource ID of the animation resource to use for
    122      * the incoming activity.  Use 0 for no animation.
    123      * @param exitResId A resource ID of the animation resource to use for
    124      * the outgoing activity.  Use 0 for no animation.
    125      * @return Returns a new ActivityOptions object that you can use to
    126      * supply these options as the options Bundle when starting an activity.
    127      */
    128     public static ActivityOptions makeCustomAnimation(Context context,
    129             int enterResId, int exitResId) {
    130         return makeCustomAnimation(context, enterResId, exitResId, null, null);
    131     }
    132 
    133     /**
    134      * Create an ActivityOptions specifying a custom animation to run when
    135      * the activity is displayed.
    136      *
    137      * @param context Who is defining this.  This is the application that the
    138      * animation resources will be loaded from.
    139      * @param enterResId A resource ID of the animation resource to use for
    140      * the incoming activity.  Use 0 for no animation.
    141      * @param exitResId A resource ID of the animation resource to use for
    142      * the outgoing activity.  Use 0 for no animation.
    143      * @param handler If <var>listener</var> is non-null this must be a valid
    144      * Handler on which to dispatch the callback; otherwise it should be null.
    145      * @param listener Optional OnAnimationStartedListener to find out when the
    146      * requested animation has started running.  If for some reason the animation
    147      * is not executed, the callback will happen immediately.
    148      * @return Returns a new ActivityOptions object that you can use to
    149      * supply these options as the options Bundle when starting an activity.
    150      * @hide
    151      */
    152     public static ActivityOptions makeCustomAnimation(Context context,
    153             int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener) {
    154         ActivityOptions opts = new ActivityOptions();
    155         opts.mPackageName = context.getPackageName();
    156         opts.mAnimationType = ANIM_CUSTOM;
    157         opts.mCustomEnterResId = enterResId;
    158         opts.mCustomExitResId = exitResId;
    159         opts.setListener(handler, listener);
    160         return opts;
    161     }
    162 
    163     private void setListener(Handler handler, OnAnimationStartedListener listener) {
    164         if (listener != null) {
    165             final Handler h = handler;
    166             final OnAnimationStartedListener finalListener = listener;
    167             mAnimationStartedListener = new IRemoteCallback.Stub() {
    168                 @Override public void sendResult(Bundle data) throws RemoteException {
    169                     h.post(new Runnable() {
    170                         @Override public void run() {
    171                             finalListener.onAnimationStarted();
    172                         }
    173                     });
    174                 }
    175             };
    176         }
    177     }
    178 
    179     /**
    180      * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
    181      * to find out when the given animation has started running.
    182      * @hide
    183      */
    184     public interface OnAnimationStartedListener {
    185         void onAnimationStarted();
    186     }
    187 
    188     /**
    189      * Create an ActivityOptions specifying an animation where the new
    190      * activity is scaled from a small originating area of the screen to
    191      * its final full representation.
    192      *
    193      * <p>If the Intent this is being used with has not set its
    194      * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
    195      * those bounds will be filled in for you based on the initial
    196      * bounds passed in here.
    197      *
    198      * @param source The View that the new activity is animating from.  This
    199      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
    200      * @param startX The x starting location of the new activity, relative to <var>source</var>.
    201      * @param startY The y starting location of the activity, relative to <var>source</var>.
    202      * @param startWidth The initial width of the new activity.
    203      * @param startHeight The initial height of the new activity.
    204      * @return Returns a new ActivityOptions object that you can use to
    205      * supply these options as the options Bundle when starting an activity.
    206      */
    207     public static ActivityOptions makeScaleUpAnimation(View source,
    208             int startX, int startY, int startWidth, int startHeight) {
    209         ActivityOptions opts = new ActivityOptions();
    210         opts.mPackageName = source.getContext().getPackageName();
    211         opts.mAnimationType = ANIM_SCALE_UP;
    212         int[] pts = new int[2];
    213         source.getLocationOnScreen(pts);
    214         opts.mStartX = pts[0] + startX;
    215         opts.mStartY = pts[1] + startY;
    216         opts.mStartWidth = startWidth;
    217         opts.mStartHeight = startHeight;
    218         return opts;
    219     }
    220 
    221     /**
    222      * Create an ActivityOptions specifying an animation where a thumbnail
    223      * is scaled from a given position to the new activity window that is
    224      * being started.
    225      *
    226      * <p>If the Intent this is being used with has not set its
    227      * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
    228      * those bounds will be filled in for you based on the initial
    229      * thumbnail location and size provided here.
    230      *
    231      * @param source The View that this thumbnail is animating from.  This
    232      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
    233      * @param thumbnail The bitmap that will be shown as the initial thumbnail
    234      * of the animation.
    235      * @param startX The x starting location of the bitmap, relative to <var>source</var>.
    236      * @param startY The y starting location of the bitmap, relative to <var>source</var>.
    237      * @return Returns a new ActivityOptions object that you can use to
    238      * supply these options as the options Bundle when starting an activity.
    239      */
    240     public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
    241             Bitmap thumbnail, int startX, int startY) {
    242         return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, null);
    243     }
    244 
    245     /**
    246      * Create an ActivityOptions specifying an animation where a thumbnail
    247      * is scaled from a given position to the new activity window that is
    248      * being started.
    249      *
    250      * @param source The View that this thumbnail is animating from.  This
    251      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
    252      * @param thumbnail The bitmap that will be shown as the initial thumbnail
    253      * of the animation.
    254      * @param startX The x starting location of the bitmap, relative to <var>source</var>.
    255      * @param startY The y starting location of the bitmap, relative to <var>source</var>.
    256      * @param listener Optional OnAnimationStartedListener to find out when the
    257      * requested animation has started running.  If for some reason the animation
    258      * is not executed, the callback will happen immediately.
    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      * @hide
    262      */
    263     public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
    264             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
    265         return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, listener, false);
    266     }
    267 
    268     /**
    269      * Create an ActivityOptions specifying an animation where a thumbnail
    270      * is scaled from a given position to the new activity window that is
    271      * being started. Before the animation, there is a short delay.
    272      *
    273      * @param source The View that this thumbnail is animating from.  This
    274      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
    275      * @param thumbnail The bitmap that will be shown as the initial thumbnail
    276      * of the animation.
    277      * @param startX The x starting location of the bitmap, relative to <var>source</var>.
    278      * @param startY The y starting location of the bitmap, relative to <var>source</var>.
    279      * @param listener Optional OnAnimationStartedListener to find out when the
    280      * requested animation has started running.  If for some reason the animation
    281      * is not executed, the callback will happen immediately.
    282      * @return Returns a new ActivityOptions object that you can use to
    283      * supply these options as the options Bundle when starting an activity.
    284      * @hide
    285      */
    286     public static ActivityOptions makeDelayedThumbnailScaleUpAnimation(View source,
    287             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
    288         return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, listener, true);
    289     }
    290 
    291     private static ActivityOptions makeThumbnailScaleUpAnimation(View source,
    292             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
    293             boolean delayed) {
    294         ActivityOptions opts = new ActivityOptions();
    295         opts.mPackageName = source.getContext().getPackageName();
    296         opts.mAnimationType = delayed ? ANIM_THUMBNAIL_DELAYED : ANIM_THUMBNAIL;
    297         opts.mThumbnail = thumbnail;
    298         int[] pts = new int[2];
    299         source.getLocationOnScreen(pts);
    300         opts.mStartX = pts[0] + startX;
    301         opts.mStartY = pts[1] + startY;
    302         opts.setListener(source.getHandler(), listener);
    303         return opts;
    304     }
    305 
    306     private ActivityOptions() {
    307     }
    308 
    309     /** @hide */
    310     public ActivityOptions(Bundle opts) {
    311         mPackageName = opts.getString(KEY_PACKAGE_NAME);
    312         mAnimationType = opts.getInt(KEY_ANIM_TYPE);
    313         if (mAnimationType == ANIM_CUSTOM) {
    314             mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
    315             mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
    316             mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
    317                     opts.getIBinder(KEY_ANIM_START_LISTENER));
    318         } else if (mAnimationType == ANIM_SCALE_UP) {
    319             mStartX = opts.getInt(KEY_ANIM_START_X, 0);
    320             mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
    321             mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0);
    322             mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0);
    323         } else if (mAnimationType == ANIM_THUMBNAIL ||
    324                 mAnimationType == ANIM_THUMBNAIL_DELAYED) {
    325             mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL);
    326             mStartX = opts.getInt(KEY_ANIM_START_X, 0);
    327             mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
    328             mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
    329                     opts.getIBinder(KEY_ANIM_START_LISTENER));
    330         }
    331     }
    332 
    333     /** @hide */
    334     public String getPackageName() {
    335         return mPackageName;
    336     }
    337 
    338     /** @hide */
    339     public int getAnimationType() {
    340         return mAnimationType;
    341     }
    342 
    343     /** @hide */
    344     public int getCustomEnterResId() {
    345         return mCustomEnterResId;
    346     }
    347 
    348     /** @hide */
    349     public int getCustomExitResId() {
    350         return mCustomExitResId;
    351     }
    352 
    353     /** @hide */
    354     public Bitmap getThumbnail() {
    355         return mThumbnail;
    356     }
    357 
    358     /** @hide */
    359     public int getStartX() {
    360         return mStartX;
    361     }
    362 
    363     /** @hide */
    364     public int getStartY() {
    365         return mStartY;
    366     }
    367 
    368     /** @hide */
    369     public int getStartWidth() {
    370         return mStartWidth;
    371     }
    372 
    373     /** @hide */
    374     public int getStartHeight() {
    375         return mStartHeight;
    376     }
    377 
    378     /** @hide */
    379     public IRemoteCallback getOnAnimationStartListener() {
    380         return mAnimationStartedListener;
    381     }
    382 
    383     /** @hide */
    384     public void abort() {
    385         if (mAnimationStartedListener != null) {
    386             try {
    387                 mAnimationStartedListener.sendResult(null);
    388             } catch (RemoteException e) {
    389             }
    390         }
    391     }
    392 
    393     /** @hide */
    394     public static void abort(Bundle options) {
    395         if (options != null) {
    396             (new ActivityOptions(options)).abort();
    397         }
    398     }
    399 
    400     /**
    401      * Update the current values in this ActivityOptions from those supplied
    402      * in <var>otherOptions</var>.  Any values
    403      * defined in <var>otherOptions</var> replace those in the base options.
    404      */
    405     public void update(ActivityOptions otherOptions) {
    406         if (otherOptions.mPackageName != null) {
    407             mPackageName = otherOptions.mPackageName;
    408         }
    409         switch (otherOptions.mAnimationType) {
    410             case ANIM_CUSTOM:
    411                 mAnimationType = otherOptions.mAnimationType;
    412                 mCustomEnterResId = otherOptions.mCustomEnterResId;
    413                 mCustomExitResId = otherOptions.mCustomExitResId;
    414                 mThumbnail = null;
    415                 if (otherOptions.mAnimationStartedListener != null) {
    416                     try {
    417                         otherOptions.mAnimationStartedListener.sendResult(null);
    418                     } catch (RemoteException e) {
    419                     }
    420                 }
    421                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
    422                 break;
    423             case ANIM_SCALE_UP:
    424                 mAnimationType = otherOptions.mAnimationType;
    425                 mStartX = otherOptions.mStartX;
    426                 mStartY = otherOptions.mStartY;
    427                 mStartWidth = otherOptions.mStartWidth;
    428                 mStartHeight = otherOptions.mStartHeight;
    429                 if (otherOptions.mAnimationStartedListener != null) {
    430                     try {
    431                         otherOptions.mAnimationStartedListener.sendResult(null);
    432                     } catch (RemoteException e) {
    433                     }
    434                 }
    435                 mAnimationStartedListener = null;
    436                 break;
    437             case ANIM_THUMBNAIL:
    438             case ANIM_THUMBNAIL_DELAYED:
    439                 mAnimationType = otherOptions.mAnimationType;
    440                 mThumbnail = otherOptions.mThumbnail;
    441                 mStartX = otherOptions.mStartX;
    442                 mStartY = otherOptions.mStartY;
    443                 if (otherOptions.mAnimationStartedListener != null) {
    444                     try {
    445                         otherOptions.mAnimationStartedListener.sendResult(null);
    446                     } catch (RemoteException e) {
    447                     }
    448                 }
    449                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
    450                 break;
    451         }
    452     }
    453 
    454     /**
    455      * Returns the created options as a Bundle, which can be passed to
    456      * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
    457      * Context.startActivity(Intent, Bundle)} and related methods.
    458      * Note that the returned Bundle is still owned by the ActivityOptions
    459      * object; you must not modify it, but can supply it to the startActivity
    460      * methods that take an options Bundle.
    461      */
    462     public Bundle toBundle() {
    463         Bundle b = new Bundle();
    464         if (mPackageName != null) {
    465             b.putString(KEY_PACKAGE_NAME, mPackageName);
    466         }
    467         switch (mAnimationType) {
    468             case ANIM_CUSTOM:
    469                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
    470                 b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
    471                 b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
    472                 b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
    473                         != null ? mAnimationStartedListener.asBinder() : null);
    474                 break;
    475             case ANIM_SCALE_UP:
    476                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
    477                 b.putInt(KEY_ANIM_START_X, mStartX);
    478                 b.putInt(KEY_ANIM_START_Y, mStartY);
    479                 b.putInt(KEY_ANIM_START_WIDTH, mStartWidth);
    480                 b.putInt(KEY_ANIM_START_HEIGHT, mStartHeight);
    481                 break;
    482             case ANIM_THUMBNAIL:
    483             case ANIM_THUMBNAIL_DELAYED:
    484                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
    485                 b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
    486                 b.putInt(KEY_ANIM_START_X, mStartX);
    487                 b.putInt(KEY_ANIM_START_Y, mStartY);
    488                 b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
    489                         != null ? mAnimationStartedListener.asBinder() : null);
    490                 break;
    491         }
    492         return b;
    493     }
    494 }
    495