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_SCALE_UP = 3;
    101     /** @hide */
    102     public static final int ANIM_THUMBNAIL_SCALE_DOWN = 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 makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true);
    266     }
    267 
    268     /**
    269      * Create an ActivityOptions specifying an animation where an activity window
    270      * is scaled from a given position to a thumbnail at a specified location.
    271      *
    272      * @param source The View that this thumbnail is animating to.  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 final thumbnail
    275      * of the animation.
    276      * @param startX The x end location of the bitmap, relative to <var>source</var>.
    277      * @param startY The y end 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 makeThumbnailScaleDownAnimation(View source,
    286             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
    287         return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, false);
    288     }
    289 
    290     private static ActivityOptions makeThumbnailAnimation(View source,
    291             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
    292             boolean scaleUp) {
    293         ActivityOptions opts = new ActivityOptions();
    294         opts.mPackageName = source.getContext().getPackageName();
    295         opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN;
    296         opts.mThumbnail = thumbnail;
    297         int[] pts = new int[2];
    298         source.getLocationOnScreen(pts);
    299         opts.mStartX = pts[0] + startX;
    300         opts.mStartY = pts[1] + startY;
    301         opts.setListener(source.getHandler(), listener);
    302         return opts;
    303     }
    304 
    305     private ActivityOptions() {
    306     }
    307 
    308     /** @hide */
    309     public ActivityOptions(Bundle opts) {
    310         mPackageName = opts.getString(KEY_PACKAGE_NAME);
    311         mAnimationType = opts.getInt(KEY_ANIM_TYPE);
    312         if (mAnimationType == ANIM_CUSTOM) {
    313             mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
    314             mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
    315             mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
    316                     opts.getIBinder(KEY_ANIM_START_LISTENER));
    317         } else if (mAnimationType == ANIM_SCALE_UP) {
    318             mStartX = opts.getInt(KEY_ANIM_START_X, 0);
    319             mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
    320             mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0);
    321             mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0);
    322         } else if (mAnimationType == ANIM_THUMBNAIL_SCALE_UP ||
    323                 mAnimationType == ANIM_THUMBNAIL_SCALE_DOWN) {
    324             mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL);
    325             mStartX = opts.getInt(KEY_ANIM_START_X, 0);
    326             mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
    327             mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
    328                     opts.getIBinder(KEY_ANIM_START_LISTENER));
    329         }
    330     }
    331 
    332     /** @hide */
    333     public String getPackageName() {
    334         return mPackageName;
    335     }
    336 
    337     /** @hide */
    338     public int getAnimationType() {
    339         return mAnimationType;
    340     }
    341 
    342     /** @hide */
    343     public int getCustomEnterResId() {
    344         return mCustomEnterResId;
    345     }
    346 
    347     /** @hide */
    348     public int getCustomExitResId() {
    349         return mCustomExitResId;
    350     }
    351 
    352     /** @hide */
    353     public Bitmap getThumbnail() {
    354         return mThumbnail;
    355     }
    356 
    357     /** @hide */
    358     public int getStartX() {
    359         return mStartX;
    360     }
    361 
    362     /** @hide */
    363     public int getStartY() {
    364         return mStartY;
    365     }
    366 
    367     /** @hide */
    368     public int getStartWidth() {
    369         return mStartWidth;
    370     }
    371 
    372     /** @hide */
    373     public int getStartHeight() {
    374         return mStartHeight;
    375     }
    376 
    377     /** @hide */
    378     public IRemoteCallback getOnAnimationStartListener() {
    379         return mAnimationStartedListener;
    380     }
    381 
    382     /** @hide */
    383     public void abort() {
    384         if (mAnimationStartedListener != null) {
    385             try {
    386                 mAnimationStartedListener.sendResult(null);
    387             } catch (RemoteException e) {
    388             }
    389         }
    390     }
    391 
    392     /** @hide */
    393     public static void abort(Bundle options) {
    394         if (options != null) {
    395             (new ActivityOptions(options)).abort();
    396         }
    397     }
    398 
    399     /**
    400      * Update the current values in this ActivityOptions from those supplied
    401      * in <var>otherOptions</var>.  Any values
    402      * defined in <var>otherOptions</var> replace those in the base options.
    403      */
    404     public void update(ActivityOptions otherOptions) {
    405         if (otherOptions.mPackageName != null) {
    406             mPackageName = otherOptions.mPackageName;
    407         }
    408         switch (otherOptions.mAnimationType) {
    409             case ANIM_CUSTOM:
    410                 mAnimationType = otherOptions.mAnimationType;
    411                 mCustomEnterResId = otherOptions.mCustomEnterResId;
    412                 mCustomExitResId = otherOptions.mCustomExitResId;
    413                 mThumbnail = null;
    414                 if (otherOptions.mAnimationStartedListener != null) {
    415                     try {
    416                         otherOptions.mAnimationStartedListener.sendResult(null);
    417                     } catch (RemoteException e) {
    418                     }
    419                 }
    420                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
    421                 break;
    422             case ANIM_SCALE_UP:
    423                 mAnimationType = otherOptions.mAnimationType;
    424                 mStartX = otherOptions.mStartX;
    425                 mStartY = otherOptions.mStartY;
    426                 mStartWidth = otherOptions.mStartWidth;
    427                 mStartHeight = otherOptions.mStartHeight;
    428                 if (otherOptions.mAnimationStartedListener != null) {
    429                     try {
    430                         otherOptions.mAnimationStartedListener.sendResult(null);
    431                     } catch (RemoteException e) {
    432                     }
    433                 }
    434                 mAnimationStartedListener = null;
    435                 break;
    436             case ANIM_THUMBNAIL_SCALE_UP:
    437             case ANIM_THUMBNAIL_SCALE_DOWN:
    438                 mAnimationType = otherOptions.mAnimationType;
    439                 mThumbnail = otherOptions.mThumbnail;
    440                 mStartX = otherOptions.mStartX;
    441                 mStartY = otherOptions.mStartY;
    442                 if (otherOptions.mAnimationStartedListener != null) {
    443                     try {
    444                         otherOptions.mAnimationStartedListener.sendResult(null);
    445                     } catch (RemoteException e) {
    446                     }
    447                 }
    448                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
    449                 break;
    450         }
    451     }
    452 
    453     /**
    454      * Returns the created options as a Bundle, which can be passed to
    455      * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
    456      * Context.startActivity(Intent, Bundle)} and related methods.
    457      * Note that the returned Bundle is still owned by the ActivityOptions
    458      * object; you must not modify it, but can supply it to the startActivity
    459      * methods that take an options Bundle.
    460      */
    461     public Bundle toBundle() {
    462         Bundle b = new Bundle();
    463         if (mPackageName != null) {
    464             b.putString(KEY_PACKAGE_NAME, mPackageName);
    465         }
    466         switch (mAnimationType) {
    467             case ANIM_CUSTOM:
    468                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
    469                 b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
    470                 b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
    471                 b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
    472                         != null ? mAnimationStartedListener.asBinder() : null);
    473                 break;
    474             case ANIM_SCALE_UP:
    475                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
    476                 b.putInt(KEY_ANIM_START_X, mStartX);
    477                 b.putInt(KEY_ANIM_START_Y, mStartY);
    478                 b.putInt(KEY_ANIM_START_WIDTH, mStartWidth);
    479                 b.putInt(KEY_ANIM_START_HEIGHT, mStartHeight);
    480                 break;
    481             case ANIM_THUMBNAIL_SCALE_UP:
    482             case ANIM_THUMBNAIL_SCALE_DOWN:
    483                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
    484                 b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
    485                 b.putInt(KEY_ANIM_START_X, mStartX);
    486                 b.putInt(KEY_ANIM_START_Y, mStartY);
    487                 b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
    488                         != null ? mAnimationStartedListener.asBinder() : null);
    489                 break;
    490         }
    491         return b;
    492     }
    493 }
    494