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 static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
     20 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
     21 
     22 import android.annotation.Nullable;
     23 import android.annotation.TestApi;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.graphics.Bitmap;
     27 import android.graphics.Rect;
     28 import android.os.Bundle;
     29 import android.os.Handler;
     30 import android.os.IRemoteCallback;
     31 import android.os.Parcelable;
     32 import android.os.RemoteException;
     33 import android.os.ResultReceiver;
     34 import android.transition.Transition;
     35 import android.transition.TransitionManager;
     36 import android.util.Pair;
     37 import android.util.Slog;
     38 import android.view.AppTransitionAnimationSpec;
     39 import android.view.View;
     40 import android.view.ViewGroup;
     41 import android.view.Window;
     42 
     43 import java.util.ArrayList;
     44 
     45 /**
     46  * Helper class for building an options Bundle that can be used with
     47  * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
     48  * Context.startActivity(Intent, Bundle)} and related methods.
     49  */
     50 public class ActivityOptions {
     51     private static final String TAG = "ActivityOptions";
     52 
     53     /**
     54      * A long in the extras delivered by {@link #requestUsageTimeReport} that contains
     55      * the total time (in ms) the user spent in the app flow.
     56      */
     57     public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
     58 
     59     /**
     60      * A Bundle in the extras delivered by {@link #requestUsageTimeReport} that contains
     61      * detailed information about the time spent in each package associated with the app;
     62      * each key is a package name, whose value is a long containing the time (in ms).
     63      */
     64     public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
     65 
     66     /**
     67      * The package name that created the options.
     68      * @hide
     69      */
     70     public static final String KEY_PACKAGE_NAME = "android:activity.packageName";
     71 
     72     /**
     73      * The bounds (window size) that the activity should be launched in. Set to null explicitly for
     74      * full screen. If the key is not found, previous bounds will be preserved.
     75      * NOTE: This value is ignored on devices that don't have
     76      * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or
     77      * {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled.
     78      * @hide
     79      */
     80     public static final String KEY_LAUNCH_BOUNDS = "android:activity.launchBounds";
     81 
     82     /**
     83      * Type of animation that arguments specify.
     84      * @hide
     85      */
     86     public static final String KEY_ANIM_TYPE = "android:activity.animType";
     87 
     88     /**
     89      * Custom enter animation resource ID.
     90      * @hide
     91      */
     92     public static final String KEY_ANIM_ENTER_RES_ID = "android:activity.animEnterRes";
     93 
     94     /**
     95      * Custom exit animation resource ID.
     96      * @hide
     97      */
     98     public static final String KEY_ANIM_EXIT_RES_ID = "android:activity.animExitRes";
     99 
    100     /**
    101      * Custom in-place animation resource ID.
    102      * @hide
    103      */
    104     public static final String KEY_ANIM_IN_PLACE_RES_ID = "android:activity.animInPlaceRes";
    105 
    106     /**
    107      * Bitmap for thumbnail animation.
    108      * @hide
    109      */
    110     public static final String KEY_ANIM_THUMBNAIL = "android:activity.animThumbnail";
    111 
    112     /**
    113      * Start X position of thumbnail animation.
    114      * @hide
    115      */
    116     public static final String KEY_ANIM_START_X = "android:activity.animStartX";
    117 
    118     /**
    119      * Start Y position of thumbnail animation.
    120      * @hide
    121      */
    122     public static final String KEY_ANIM_START_Y = "android:activity.animStartY";
    123 
    124     /**
    125      * Initial width of the animation.
    126      * @hide
    127      */
    128     public static final String KEY_ANIM_WIDTH = "android:activity.animWidth";
    129 
    130     /**
    131      * Initial height of the animation.
    132      * @hide
    133      */
    134     public static final String KEY_ANIM_HEIGHT = "android:activity.animHeight";
    135 
    136     /**
    137      * Callback for when animation is started.
    138      * @hide
    139      */
    140     public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener";
    141 
    142     /**
    143      * Callback for when the last frame of the animation is played.
    144      * @hide
    145      */
    146     private static final String KEY_ANIMATION_FINISHED_LISTENER =
    147             "android:activity.animationFinishedListener";
    148 
    149     /**
    150      * Descriptions of app transition animations to be played during the activity launch.
    151      */
    152     private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";
    153 
    154     /**
    155      * The stack id the activity should be launched into.
    156      * @hide
    157      */
    158     private static final String KEY_LAUNCH_STACK_ID = "android.activity.launchStackId";
    159 
    160     /**
    161      * The task id the activity should be launched into.
    162      * @hide
    163      */
    164     private static final String KEY_LAUNCH_TASK_ID = "android.activity.launchTaskId";
    165 
    166     /**
    167      * See {@link #setTaskOverlay}.
    168      * @hide
    169      */
    170     private static final String KEY_TASK_OVERLAY = "android.activity.taskOverlay";
    171 
    172     /**
    173      * Where the docked stack should be positioned.
    174      * @hide
    175      */
    176     private static final String KEY_DOCK_CREATE_MODE = "android:activity.dockCreateMode";
    177 
    178     /**
    179      * For Activity transitions, the calling Activity's TransitionListener used to
    180      * notify the called Activity when the shared element and the exit transitions
    181      * complete.
    182      */
    183     private static final String KEY_TRANSITION_COMPLETE_LISTENER
    184             = "android:activity.transitionCompleteListener";
    185 
    186     private static final String KEY_TRANSITION_IS_RETURNING
    187             = "android:activity.transitionIsReturning";
    188     private static final String KEY_TRANSITION_SHARED_ELEMENTS
    189             = "android:activity.sharedElementNames";
    190     private static final String KEY_RESULT_DATA = "android:activity.resultData";
    191     private static final String KEY_RESULT_CODE = "android:activity.resultCode";
    192     private static final String KEY_EXIT_COORDINATOR_INDEX
    193             = "android:activity.exitCoordinatorIndex";
    194 
    195     private static final String KEY_USAGE_TIME_REPORT = "android:activity.usageTimeReport";
    196     private static final String KEY_ROTATION_ANIMATION_HINT = "android:activity.rotationAnimationHint";
    197 
    198     /** @hide */
    199     public static final int ANIM_NONE = 0;
    200     /** @hide */
    201     public static final int ANIM_CUSTOM = 1;
    202     /** @hide */
    203     public static final int ANIM_SCALE_UP = 2;
    204     /** @hide */
    205     public static final int ANIM_THUMBNAIL_SCALE_UP = 3;
    206     /** @hide */
    207     public static final int ANIM_THUMBNAIL_SCALE_DOWN = 4;
    208     /** @hide */
    209     public static final int ANIM_SCENE_TRANSITION = 5;
    210     /** @hide */
    211     public static final int ANIM_DEFAULT = 6;
    212     /** @hide */
    213     public static final int ANIM_LAUNCH_TASK_BEHIND = 7;
    214     /** @hide */
    215     public static final int ANIM_THUMBNAIL_ASPECT_SCALE_UP = 8;
    216     /** @hide */
    217     public static final int ANIM_THUMBNAIL_ASPECT_SCALE_DOWN = 9;
    218     /** @hide */
    219     public static final int ANIM_CUSTOM_IN_PLACE = 10;
    220     /** @hide */
    221     public static final int ANIM_CLIP_REVEAL = 11;
    222 
    223     private String mPackageName;
    224     private Rect mLaunchBounds;
    225     private int mAnimationType = ANIM_NONE;
    226     private int mCustomEnterResId;
    227     private int mCustomExitResId;
    228     private int mCustomInPlaceResId;
    229     private Bitmap mThumbnail;
    230     private int mStartX;
    231     private int mStartY;
    232     private int mWidth;
    233     private int mHeight;
    234     private IRemoteCallback mAnimationStartedListener;
    235     private IRemoteCallback mAnimationFinishedListener;
    236     private ResultReceiver mTransitionReceiver;
    237     private boolean mIsReturning;
    238     private ArrayList<String> mSharedElementNames;
    239     private Intent mResultData;
    240     private int mResultCode;
    241     private int mExitCoordinatorIndex;
    242     private PendingIntent mUsageTimeReport;
    243     private int mLaunchStackId = INVALID_STACK_ID;
    244     private int mLaunchTaskId = -1;
    245     private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
    246     private boolean mTaskOverlay;
    247     private AppTransitionAnimationSpec mAnimSpecs[];
    248     private int mRotationAnimationHint = -1;
    249 
    250     /**
    251      * Create an ActivityOptions specifying a custom animation to run when
    252      * the activity is displayed.
    253      *
    254      * @param context Who is defining this.  This is the application that the
    255      * animation resources will be loaded from.
    256      * @param enterResId A resource ID of the animation resource to use for
    257      * the incoming activity.  Use 0 for no animation.
    258      * @param exitResId A resource ID of the animation resource to use for
    259      * the outgoing activity.  Use 0 for no animation.
    260      * @return Returns a new ActivityOptions object that you can use to
    261      * supply these options as the options Bundle when starting an activity.
    262      */
    263     public static ActivityOptions makeCustomAnimation(Context context,
    264             int enterResId, int exitResId) {
    265         return makeCustomAnimation(context, enterResId, exitResId, null, null);
    266     }
    267 
    268     /**
    269      * Create an ActivityOptions specifying a custom animation to run when
    270      * the activity is displayed.
    271      *
    272      * @param context Who is defining this.  This is the application that the
    273      * animation resources will be loaded from.
    274      * @param enterResId A resource ID of the animation resource to use for
    275      * the incoming activity.  Use 0 for no animation.
    276      * @param exitResId A resource ID of the animation resource to use for
    277      * the outgoing activity.  Use 0 for no animation.
    278      * @param handler If <var>listener</var> is non-null this must be a valid
    279      * Handler on which to dispatch the callback; otherwise it should be null.
    280      * @param listener Optional OnAnimationStartedListener to find out when the
    281      * requested animation has started running.  If for some reason the animation
    282      * is not executed, the callback will happen immediately.
    283      * @return Returns a new ActivityOptions object that you can use to
    284      * supply these options as the options Bundle when starting an activity.
    285      * @hide
    286      */
    287     public static ActivityOptions makeCustomAnimation(Context context,
    288             int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener) {
    289         ActivityOptions opts = new ActivityOptions();
    290         opts.mPackageName = context.getPackageName();
    291         opts.mAnimationType = ANIM_CUSTOM;
    292         opts.mCustomEnterResId = enterResId;
    293         opts.mCustomExitResId = exitResId;
    294         opts.setOnAnimationStartedListener(handler, listener);
    295         return opts;
    296     }
    297 
    298     /**
    299      * Creates an ActivityOptions specifying a custom animation to run in place on an existing
    300      * activity.
    301      *
    302      * @param context Who is defining this.  This is the application that the
    303      * animation resources will be loaded from.
    304      * @param animId A resource ID of the animation resource to use for
    305      * the incoming activity.
    306      * @return Returns a new ActivityOptions object that you can use to
    307      * supply these options as the options Bundle when running an in-place animation.
    308      * @hide
    309      */
    310     public static ActivityOptions makeCustomInPlaceAnimation(Context context, int animId) {
    311         if (animId == 0) {
    312             throw new RuntimeException("You must specify a valid animation.");
    313         }
    314 
    315         ActivityOptions opts = new ActivityOptions();
    316         opts.mPackageName = context.getPackageName();
    317         opts.mAnimationType = ANIM_CUSTOM_IN_PLACE;
    318         opts.mCustomInPlaceResId = animId;
    319         return opts;
    320     }
    321 
    322     private void setOnAnimationStartedListener(final Handler handler,
    323             final OnAnimationStartedListener listener) {
    324         if (listener != null) {
    325             mAnimationStartedListener = new IRemoteCallback.Stub() {
    326                 @Override
    327                 public void sendResult(Bundle data) throws RemoteException {
    328                     handler.post(new Runnable() {
    329                         @Override public void run() {
    330                             listener.onAnimationStarted();
    331                         }
    332                     });
    333                 }
    334             };
    335         }
    336     }
    337 
    338     /**
    339      * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
    340      * to find out when the given animation has started running.
    341      * @hide
    342      */
    343     public interface OnAnimationStartedListener {
    344         void onAnimationStarted();
    345     }
    346 
    347     private void setOnAnimationFinishedListener(final Handler handler,
    348             final OnAnimationFinishedListener listener) {
    349         if (listener != null) {
    350             mAnimationFinishedListener = new IRemoteCallback.Stub() {
    351                 @Override
    352                 public void sendResult(Bundle data) throws RemoteException {
    353                     handler.post(new Runnable() {
    354                         @Override
    355                         public void run() {
    356                             listener.onAnimationFinished();
    357                         }
    358                     });
    359                 }
    360             };
    361         }
    362     }
    363 
    364     /**
    365      * Callback for use with {@link ActivityOptions#makeThumbnailAspectScaleDownAnimation}
    366      * to find out when the given animation has drawn its last frame.
    367      * @hide
    368      */
    369     public interface OnAnimationFinishedListener {
    370         void onAnimationFinished();
    371     }
    372 
    373     /**
    374      * Create an ActivityOptions specifying an animation where the new
    375      * activity is scaled from a small originating area of the screen to
    376      * its final full representation.
    377      *
    378      * <p>If the Intent this is being used with has not set its
    379      * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
    380      * those bounds will be filled in for you based on the initial
    381      * bounds passed in here.
    382      *
    383      * @param source The View that the new activity is animating from.  This
    384      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
    385      * @param startX The x starting location of the new activity, relative to <var>source</var>.
    386      * @param startY The y starting location of the activity, relative to <var>source</var>.
    387      * @param width The initial width of the new activity.
    388      * @param height The initial height of the new activity.
    389      * @return Returns a new ActivityOptions object that you can use to
    390      * supply these options as the options Bundle when starting an activity.
    391      */
    392     public static ActivityOptions makeScaleUpAnimation(View source,
    393             int startX, int startY, int width, int height) {
    394         ActivityOptions opts = new ActivityOptions();
    395         opts.mPackageName = source.getContext().getPackageName();
    396         opts.mAnimationType = ANIM_SCALE_UP;
    397         int[] pts = new int[2];
    398         source.getLocationOnScreen(pts);
    399         opts.mStartX = pts[0] + startX;
    400         opts.mStartY = pts[1] + startY;
    401         opts.mWidth = width;
    402         opts.mHeight = height;
    403         return opts;
    404     }
    405 
    406     /**
    407      * Create an ActivityOptions specifying an animation where the new
    408      * activity is revealed from a small originating area of the screen to
    409      * its final full representation.
    410      *
    411      * @param source The View that the new activity is animating from.  This
    412      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
    413      * @param startX The x starting location of the new activity, relative to <var>source</var>.
    414      * @param startY The y starting location of the activity, relative to <var>source</var>.
    415      * @param width The initial width of the new activity.
    416      * @param height The initial height of the new activity.
    417      * @return Returns a new ActivityOptions object that you can use to
    418      * supply these options as the options Bundle when starting an activity.
    419      */
    420     public static ActivityOptions makeClipRevealAnimation(View source,
    421             int startX, int startY, int width, int height) {
    422         ActivityOptions opts = new ActivityOptions();
    423         opts.mAnimationType = ANIM_CLIP_REVEAL;
    424         int[] pts = new int[2];
    425         source.getLocationOnScreen(pts);
    426         opts.mStartX = pts[0] + startX;
    427         opts.mStartY = pts[1] + startY;
    428         opts.mWidth = width;
    429         opts.mHeight = height;
    430         return opts;
    431     }
    432 
    433     /**
    434      * Create an ActivityOptions specifying an animation where a thumbnail
    435      * is scaled from a given position to the new activity window that is
    436      * being started.
    437      *
    438      * <p>If the Intent this is being used with has not set its
    439      * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
    440      * those bounds will be filled in for you based on the initial
    441      * thumbnail location and size provided here.
    442      *
    443      * @param source The View that this thumbnail is animating from.  This
    444      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
    445      * @param thumbnail The bitmap that will be shown as the initial thumbnail
    446      * of the animation.
    447      * @param startX The x starting location of the bitmap, relative to <var>source</var>.
    448      * @param startY The y starting location of the bitmap, relative to <var>source</var>.
    449      * @return Returns a new ActivityOptions object that you can use to
    450      * supply these options as the options Bundle when starting an activity.
    451      */
    452     public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
    453             Bitmap thumbnail, int startX, int startY) {
    454         return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, null);
    455     }
    456 
    457     /**
    458      * Create an ActivityOptions specifying an animation where a thumbnail
    459      * is scaled from a given position to the new activity window that is
    460      * being started.
    461      *
    462      * @param source The View that this thumbnail is animating from.  This
    463      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
    464      * @param thumbnail The bitmap that will be shown as the initial thumbnail
    465      * of the animation.
    466      * @param startX The x starting location of the bitmap, relative to <var>source</var>.
    467      * @param startY The y starting location of the bitmap, relative to <var>source</var>.
    468      * @param listener Optional OnAnimationStartedListener to find out when the
    469      * requested animation has started running.  If for some reason the animation
    470      * is not executed, the callback will happen immediately.
    471      * @return Returns a new ActivityOptions object that you can use to
    472      * supply these options as the options Bundle when starting an activity.
    473      * @hide
    474      */
    475     public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
    476             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
    477         return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true);
    478     }
    479 
    480     /**
    481      * Create an ActivityOptions specifying an animation where an activity window
    482      * is scaled from a given position to a thumbnail at a specified location.
    483      *
    484      * @param source The View that this thumbnail is animating to.  This
    485      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
    486      * @param thumbnail The bitmap that will be shown as the final thumbnail
    487      * of the animation.
    488      * @param startX The x end location of the bitmap, relative to <var>source</var>.
    489      * @param startY The y end location of the bitmap, relative to <var>source</var>.
    490      * @param listener Optional OnAnimationStartedListener to find out when the
    491      * requested animation has started running.  If for some reason the animation
    492      * is not executed, the callback will happen immediately.
    493      * @return Returns a new ActivityOptions object that you can use to
    494      * supply these options as the options Bundle when starting an activity.
    495      * @hide
    496      */
    497     public static ActivityOptions makeThumbnailScaleDownAnimation(View source,
    498             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
    499         return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, false);
    500     }
    501 
    502     private static ActivityOptions makeThumbnailAnimation(View source,
    503             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
    504             boolean scaleUp) {
    505         ActivityOptions opts = new ActivityOptions();
    506         opts.mPackageName = source.getContext().getPackageName();
    507         opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN;
    508         opts.mThumbnail = thumbnail;
    509         int[] pts = new int[2];
    510         source.getLocationOnScreen(pts);
    511         opts.mStartX = pts[0] + startX;
    512         opts.mStartY = pts[1] + startY;
    513         opts.setOnAnimationStartedListener(source.getHandler(), listener);
    514         return opts;
    515     }
    516 
    517     /**
    518      * Create an ActivityOptions specifying an animation where the new activity
    519      * window and a thumbnail is aspect-scaled to a new location.
    520      *
    521      * @param source The View that this thumbnail is animating from.  This
    522      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
    523      * @param thumbnail The bitmap that will be shown as the initial thumbnail
    524      * of the animation.
    525      * @param startX The x starting location of the bitmap, relative to <var>source</var>.
    526      * @param startY The y starting location of the bitmap, relative to <var>source</var>.
    527      * @param handler If <var>listener</var> is non-null this must be a valid
    528      * Handler on which to dispatch the callback; otherwise it should be null.
    529      * @param listener Optional OnAnimationStartedListener to find out when the
    530      * requested animation has started running.  If for some reason the animation
    531      * is not executed, the callback will happen immediately.
    532      * @return Returns a new ActivityOptions object that you can use to
    533      * supply these options as the options Bundle when starting an activity.
    534      * @hide
    535      */
    536     public static ActivityOptions makeThumbnailAspectScaleUpAnimation(View source,
    537             Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight,
    538             Handler handler, OnAnimationStartedListener listener) {
    539         return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY,
    540                 targetWidth, targetHeight, handler, listener, true);
    541     }
    542 
    543     /**
    544      * Create an ActivityOptions specifying an animation where the new activity
    545      * window and a thumbnail is aspect-scaled to a new location.
    546      *
    547      * @param source The View that this thumbnail is animating to.  This
    548      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
    549      * @param thumbnail The bitmap that will be shown as the final thumbnail
    550      * of the animation.
    551      * @param startX The x end location of the bitmap, relative to <var>source</var>.
    552      * @param startY The y end location of the bitmap, relative to <var>source</var>.
    553      * @param handler If <var>listener</var> is non-null this must be a valid
    554      * Handler on which to dispatch the callback; otherwise it should be null.
    555      * @param listener Optional OnAnimationStartedListener to find out when the
    556      * requested animation has started running.  If for some reason the animation
    557      * is not executed, the callback will happen immediately.
    558      * @return Returns a new ActivityOptions object that you can use to
    559      * supply these options as the options Bundle when starting an activity.
    560      * @hide
    561      */
    562     public static ActivityOptions makeThumbnailAspectScaleDownAnimation(View source,
    563             Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight,
    564             Handler handler, OnAnimationStartedListener listener) {
    565         return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY,
    566                 targetWidth, targetHeight, handler, listener, false);
    567     }
    568 
    569     private static ActivityOptions makeAspectScaledThumbnailAnimation(View source, Bitmap thumbnail,
    570             int startX, int startY, int targetWidth, int targetHeight,
    571             Handler handler, OnAnimationStartedListener listener, boolean scaleUp) {
    572         ActivityOptions opts = new ActivityOptions();
    573         opts.mPackageName = source.getContext().getPackageName();
    574         opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_ASPECT_SCALE_UP :
    575                 ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
    576         opts.mThumbnail = thumbnail;
    577         int[] pts = new int[2];
    578         source.getLocationOnScreen(pts);
    579         opts.mStartX = pts[0] + startX;
    580         opts.mStartY = pts[1] + startY;
    581         opts.mWidth = targetWidth;
    582         opts.mHeight = targetHeight;
    583         opts.setOnAnimationStartedListener(handler, listener);
    584         return opts;
    585     }
    586 
    587     /** @hide */
    588     public static ActivityOptions makeThumbnailAspectScaleDownAnimation(View source,
    589             AppTransitionAnimationSpec[] specs, Handler handler,
    590             OnAnimationStartedListener onAnimationStartedListener,
    591             OnAnimationFinishedListener onAnimationFinishedListener) {
    592         ActivityOptions opts = new ActivityOptions();
    593         opts.mPackageName = source.getContext().getPackageName();
    594         opts.mAnimationType = ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
    595         opts.mAnimSpecs = specs;
    596         opts.setOnAnimationStartedListener(handler, onAnimationStartedListener);
    597         opts.setOnAnimationFinishedListener(handler, onAnimationFinishedListener);
    598         return opts;
    599     }
    600 
    601     /**
    602      * Create an ActivityOptions to transition between Activities using cross-Activity scene
    603      * animations. This method carries the position of one shared element to the started Activity.
    604      * The position of <code>sharedElement</code> will be used as the epicenter for the
    605      * exit Transition. The position of the shared element in the launched Activity will be the
    606      * epicenter of its entering Transition.
    607      *
    608      * <p>This requires {@link android.view.Window#FEATURE_ACTIVITY_TRANSITIONS} to be
    609      * enabled on the calling Activity to cause an exit transition. The same must be in
    610      * the called Activity to get an entering transition.</p>
    611      * @param activity The Activity whose window contains the shared elements.
    612      * @param sharedElement The View to transition to the started Activity.
    613      * @param sharedElementName The shared element name as used in the target Activity. This
    614      *                          must not be null.
    615      * @return Returns a new ActivityOptions object that you can use to
    616      *         supply these options as the options Bundle when starting an activity.
    617      * @see android.transition.Transition#setEpicenterCallback(
    618      *          android.transition.Transition.EpicenterCallback)
    619      */
    620     public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
    621             View sharedElement, String sharedElementName) {
    622         return makeSceneTransitionAnimation(activity, Pair.create(sharedElement, sharedElementName));
    623     }
    624 
    625     /**
    626      * Create an ActivityOptions to transition between Activities using cross-Activity scene
    627      * animations. This method carries the position of multiple shared elements to the started
    628      * Activity. The position of the first element in sharedElements
    629      * will be used as the epicenter for the exit Transition. The position of the associated
    630      * shared element in the launched Activity will be the epicenter of its entering Transition.
    631      *
    632      * <p>This requires {@link android.view.Window#FEATURE_ACTIVITY_TRANSITIONS} to be
    633      * enabled on the calling Activity to cause an exit transition. The same must be in
    634      * the called Activity to get an entering transition.</p>
    635      * @param activity The Activity whose window contains the shared elements.
    636      * @param sharedElements The names of the shared elements to transfer to the called
    637      *                       Activity and their associated Views. The Views must each have
    638      *                       a unique shared element name.
    639      * @return Returns a new ActivityOptions object that you can use to
    640      *         supply these options as the options Bundle when starting an activity.
    641      * @see android.transition.Transition#setEpicenterCallback(
    642      *          android.transition.Transition.EpicenterCallback)
    643      */
    644     @SafeVarargs
    645     public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
    646             Pair<View, String>... sharedElements) {
    647         ActivityOptions opts = new ActivityOptions();
    648         makeSceneTransitionAnimation(activity, activity.getWindow(), opts,
    649                 activity.mExitTransitionListener, sharedElements);
    650         return opts;
    651     }
    652 
    653     /**
    654      * Call this immediately prior to startActivity to begin a shared element transition
    655      * from a non-Activity. The window must support Window.FEATURE_ACTIVITY_TRANSITIONS.
    656      * The exit transition will start immediately and the shared element transition will
    657      * start once the launched Activity's shared element is ready.
    658      * <p>
    659      * When all transitions have completed and the shared element has been transfered,
    660      * the window's decor View will have its visibility set to View.GONE.
    661      *
    662      * @hide
    663      */
    664     @SafeVarargs
    665     public static ActivityOptions startSharedElementAnimation(Window window,
    666             Pair<View, String>... sharedElements) {
    667         ActivityOptions opts = new ActivityOptions();
    668         final View decorView = window.getDecorView();
    669         if (decorView == null) {
    670             return opts;
    671         }
    672         final ExitTransitionCoordinator exit =
    673                 makeSceneTransitionAnimation(null, window, opts, null, sharedElements);
    674         if (exit != null) {
    675             HideWindowListener listener = new HideWindowListener(window, exit);
    676             exit.setHideSharedElementsCallback(listener);
    677             exit.startExit();
    678         }
    679         return opts;
    680     }
    681 
    682     /**
    683      * This method should be called when the {@link #startSharedElementAnimation(Window, Pair[])}
    684      * animation must be stopped and the Views reset. This can happen if there was an error
    685      * from startActivity or a springboard activity and the animation should stop and reset.
    686      *
    687      * @hide
    688      */
    689     public static void stopSharedElementAnimation(Window window) {
    690         final View decorView = window.getDecorView();
    691         if (decorView == null) {
    692             return;
    693         }
    694         final ExitTransitionCoordinator exit = (ExitTransitionCoordinator)
    695                 decorView.getTag(com.android.internal.R.id.cross_task_transition);
    696         if (exit != null) {
    697             exit.cancelPendingTransitions();
    698             decorView.setTagInternal(com.android.internal.R.id.cross_task_transition, null);
    699             TransitionManager.endTransitions((ViewGroup) decorView);
    700             exit.resetViews();
    701             exit.clearState();
    702             decorView.setVisibility(View.VISIBLE);
    703         }
    704     }
    705 
    706     static ExitTransitionCoordinator makeSceneTransitionAnimation(Activity activity, Window window,
    707             ActivityOptions opts, SharedElementCallback callback,
    708             Pair<View, String>[] sharedElements) {
    709         if (!window.hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) {
    710             opts.mAnimationType = ANIM_DEFAULT;
    711             return null;
    712         }
    713         opts.mAnimationType = ANIM_SCENE_TRANSITION;
    714 
    715         ArrayList<String> names = new ArrayList<String>();
    716         ArrayList<View> views = new ArrayList<View>();
    717 
    718         if (sharedElements != null) {
    719             for (int i = 0; i < sharedElements.length; i++) {
    720                 Pair<View, String> sharedElement = sharedElements[i];
    721                 String sharedElementName = sharedElement.second;
    722                 if (sharedElementName == null) {
    723                     throw new IllegalArgumentException("Shared element name must not be null");
    724                 }
    725                 names.add(sharedElementName);
    726                 View view = sharedElement.first;
    727                 if (view == null) {
    728                     throw new IllegalArgumentException("Shared element must not be null");
    729                 }
    730                 views.add(sharedElement.first);
    731             }
    732         }
    733 
    734         ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, window,
    735                 callback, names, names, views, false);
    736         opts.mTransitionReceiver = exit;
    737         opts.mSharedElementNames = names;
    738         opts.mIsReturning = (activity == null);
    739         if (activity == null) {
    740             opts.mExitCoordinatorIndex = -1;
    741         } else {
    742             opts.mExitCoordinatorIndex =
    743                     activity.mActivityTransitionState.addExitTransitionCoordinator(exit);
    744         }
    745         return exit;
    746     }
    747 
    748     /** @hide */
    749     static ActivityOptions makeSceneTransitionAnimation(Activity activity,
    750             ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames,
    751             int resultCode, Intent resultData) {
    752         ActivityOptions opts = new ActivityOptions();
    753         opts.mAnimationType = ANIM_SCENE_TRANSITION;
    754         opts.mSharedElementNames = sharedElementNames;
    755         opts.mTransitionReceiver = exitCoordinator;
    756         opts.mIsReturning = true;
    757         opts.mResultCode = resultCode;
    758         opts.mResultData = resultData;
    759         opts.mExitCoordinatorIndex =
    760                 activity.mActivityTransitionState.addExitTransitionCoordinator(exitCoordinator);
    761         return opts;
    762     }
    763 
    764     /**
    765      * If set along with Intent.FLAG_ACTIVITY_NEW_DOCUMENT then the task being launched will not be
    766      * presented to the user but will instead be only available through the recents task list.
    767      * In addition, the new task wil be affiliated with the launching activity's task.
    768      * Affiliated tasks are grouped together in the recents task list.
    769      *
    770      * <p>This behavior is not supported for activities with {@link
    771      * android.R.styleable#AndroidManifestActivity_launchMode launchMode} values of
    772      * <code>singleInstance</code> or <code>singleTask</code>.
    773      */
    774     public static ActivityOptions makeTaskLaunchBehind() {
    775         final ActivityOptions opts = new ActivityOptions();
    776         opts.mAnimationType = ANIM_LAUNCH_TASK_BEHIND;
    777         return opts;
    778     }
    779 
    780     /**
    781      * Create a basic ActivityOptions that has no special animation associated with it.
    782      * Other options can still be set.
    783      */
    784     public static ActivityOptions makeBasic() {
    785         final ActivityOptions opts = new ActivityOptions();
    786         return opts;
    787     }
    788 
    789     /** @hide */
    790     public boolean getLaunchTaskBehind() {
    791         return mAnimationType == ANIM_LAUNCH_TASK_BEHIND;
    792     }
    793 
    794     private ActivityOptions() {
    795     }
    796 
    797     /** @hide */
    798     public ActivityOptions(Bundle opts) {
    799         // If the remote side sent us bad parcelables, they won't get the
    800         // results they want, which is their loss.
    801         opts.setDefusable(true);
    802 
    803         mPackageName = opts.getString(KEY_PACKAGE_NAME);
    804         try {
    805             mUsageTimeReport = opts.getParcelable(KEY_USAGE_TIME_REPORT);
    806         } catch (RuntimeException e) {
    807             Slog.w(TAG, e);
    808         }
    809         mLaunchBounds = opts.getParcelable(KEY_LAUNCH_BOUNDS);
    810         mAnimationType = opts.getInt(KEY_ANIM_TYPE);
    811         switch (mAnimationType) {
    812             case ANIM_CUSTOM:
    813                 mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
    814                 mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
    815                 mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
    816                         opts.getBinder(KEY_ANIM_START_LISTENER));
    817                 break;
    818 
    819             case ANIM_CUSTOM_IN_PLACE:
    820                 mCustomInPlaceResId = opts.getInt(KEY_ANIM_IN_PLACE_RES_ID, 0);
    821                 break;
    822 
    823             case ANIM_SCALE_UP:
    824             case ANIM_CLIP_REVEAL:
    825                 mStartX = opts.getInt(KEY_ANIM_START_X, 0);
    826                 mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
    827                 mWidth = opts.getInt(KEY_ANIM_WIDTH, 0);
    828                 mHeight = opts.getInt(KEY_ANIM_HEIGHT, 0);
    829                 break;
    830 
    831             case ANIM_THUMBNAIL_SCALE_UP:
    832             case ANIM_THUMBNAIL_SCALE_DOWN:
    833             case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
    834             case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
    835                 mThumbnail = (Bitmap) opts.getParcelable(KEY_ANIM_THUMBNAIL);
    836                 mStartX = opts.getInt(KEY_ANIM_START_X, 0);
    837                 mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
    838                 mWidth = opts.getInt(KEY_ANIM_WIDTH, 0);
    839                 mHeight = opts.getInt(KEY_ANIM_HEIGHT, 0);
    840                 mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
    841                         opts.getBinder(KEY_ANIM_START_LISTENER));
    842                 break;
    843 
    844             case ANIM_SCENE_TRANSITION:
    845                 mTransitionReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
    846                 mIsReturning = opts.getBoolean(KEY_TRANSITION_IS_RETURNING, false);
    847                 mSharedElementNames = opts.getStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS);
    848                 mResultData = opts.getParcelable(KEY_RESULT_DATA);
    849                 mResultCode = opts.getInt(KEY_RESULT_CODE);
    850                 mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
    851                 break;
    852         }
    853         mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID);
    854         mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
    855         mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
    856         mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
    857         if (opts.containsKey(KEY_ANIM_SPECS)) {
    858             Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS);
    859             mAnimSpecs = new AppTransitionAnimationSpec[specs.length];
    860             for (int i = specs.length - 1; i >= 0; i--) {
    861                 mAnimSpecs[i] = (AppTransitionAnimationSpec) specs[i];
    862             }
    863         }
    864         if (opts.containsKey(KEY_ANIMATION_FINISHED_LISTENER)) {
    865             mAnimationFinishedListener = IRemoteCallback.Stub.asInterface(
    866                     opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER));
    867         }
    868         mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT);
    869     }
    870 
    871     /**
    872      * Sets the bounds (window size) that the activity should be launched in.
    873      * Rect position should be provided in pixels and in screen coordinates.
    874      * Set to null explicitly for fullscreen.
    875      * <p>
    876      * <strong>NOTE:<strong/> This value is ignored on devices that don't have
    877      * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or
    878      * {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled.
    879      * @param screenSpacePixelRect Launch bounds to use for the activity or null for fullscreen.
    880      */
    881     public ActivityOptions setLaunchBounds(@Nullable Rect screenSpacePixelRect) {
    882         mLaunchBounds = screenSpacePixelRect != null ? new Rect(screenSpacePixelRect) : null;
    883         return this;
    884     }
    885 
    886     /** @hide */
    887     public String getPackageName() {
    888         return mPackageName;
    889     }
    890 
    891     /**
    892      * Returns the bounds that should be used to launch the activity.
    893      * @see #setLaunchBounds(Rect)
    894      * @return Bounds used to launch the activity.
    895      */
    896     @Nullable
    897     public Rect getLaunchBounds() {
    898         return mLaunchBounds;
    899     }
    900 
    901     /** @hide */
    902     public int getAnimationType() {
    903         return mAnimationType;
    904     }
    905 
    906     /** @hide */
    907     public int getCustomEnterResId() {
    908         return mCustomEnterResId;
    909     }
    910 
    911     /** @hide */
    912     public int getCustomExitResId() {
    913         return mCustomExitResId;
    914     }
    915 
    916     /** @hide */
    917     public int getCustomInPlaceResId() {
    918         return mCustomInPlaceResId;
    919     }
    920 
    921     /** @hide */
    922     public Bitmap getThumbnail() {
    923         return mThumbnail;
    924     }
    925 
    926     /** @hide */
    927     public int getStartX() {
    928         return mStartX;
    929     }
    930 
    931     /** @hide */
    932     public int getStartY() {
    933         return mStartY;
    934     }
    935 
    936     /** @hide */
    937     public int getWidth() {
    938         return mWidth;
    939     }
    940 
    941     /** @hide */
    942     public int getHeight() {
    943         return mHeight;
    944     }
    945 
    946     /** @hide */
    947     public IRemoteCallback getOnAnimationStartListener() {
    948         return mAnimationStartedListener;
    949     }
    950 
    951     /** @hide */
    952     public IRemoteCallback getAnimationFinishedListener() {
    953         return mAnimationFinishedListener;
    954     }
    955 
    956     /** @hide */
    957     public int getExitCoordinatorKey() { return mExitCoordinatorIndex; }
    958 
    959     /** @hide */
    960     public void abort() {
    961         if (mAnimationStartedListener != null) {
    962             try {
    963                 mAnimationStartedListener.sendResult(null);
    964             } catch (RemoteException e) {
    965             }
    966         }
    967     }
    968 
    969     /** @hide */
    970     public boolean isReturning() {
    971         return mIsReturning;
    972     }
    973 
    974     /**
    975      * Returns whether or not the ActivityOptions was created with
    976      * {@link #startSharedElementAnimation(Window, Pair[])}.
    977      *
    978      * @hide
    979      */
    980     boolean isCrossTask() {
    981         return mExitCoordinatorIndex < 0;
    982     }
    983 
    984     /** @hide */
    985     public ArrayList<String> getSharedElementNames() {
    986         return mSharedElementNames;
    987     }
    988 
    989     /** @hide */
    990     public ResultReceiver getResultReceiver() { return mTransitionReceiver; }
    991 
    992     /** @hide */
    993     public int getResultCode() { return mResultCode; }
    994 
    995     /** @hide */
    996     public Intent getResultData() { return mResultData; }
    997 
    998     /** @hide */
    999     public PendingIntent getUsageTimeReport() {
   1000         return mUsageTimeReport;
   1001     }
   1002 
   1003     /** @hide */
   1004     public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; }
   1005 
   1006     /** @hide */
   1007     public static ActivityOptions fromBundle(Bundle bOptions) {
   1008         return bOptions != null ? new ActivityOptions(bOptions) : null;
   1009     }
   1010 
   1011     /** @hide */
   1012     public static void abort(ActivityOptions options) {
   1013         if (options != null) {
   1014             options.abort();
   1015         }
   1016     }
   1017 
   1018     /** @hide */
   1019     public int getLaunchStackId() {
   1020         return mLaunchStackId;
   1021     }
   1022 
   1023     /** @hide */
   1024     @TestApi
   1025     public void setLaunchStackId(int launchStackId) {
   1026         mLaunchStackId = launchStackId;
   1027     }
   1028 
   1029     /**
   1030      * Sets the task the activity will be launched in.
   1031      * @hide
   1032      */
   1033     public void setLaunchTaskId(int taskId) {
   1034         mLaunchTaskId = taskId;
   1035     }
   1036 
   1037     /**
   1038      * @hide
   1039      */
   1040     public int getLaunchTaskId() {
   1041         return mLaunchTaskId;
   1042     }
   1043 
   1044     /**
   1045      * Set's whether the activity launched with this option should be a task overlay. That is the
   1046      * activity will always be the top activity of the task and doesn't cause the task to be moved
   1047      * to the front when it is added.
   1048      * @hide
   1049      */
   1050     public void setTaskOverlay(boolean taskOverlay) {
   1051         mTaskOverlay = taskOverlay;
   1052     }
   1053 
   1054     /**
   1055      * @hide
   1056      */
   1057     public boolean getTaskOverlay() {
   1058         return mTaskOverlay;
   1059     }
   1060 
   1061     /** @hide */
   1062     public int getDockCreateMode() {
   1063         return mDockCreateMode;
   1064     }
   1065 
   1066     /** @hide */
   1067     public void setDockCreateMode(int dockCreateMode) {
   1068         mDockCreateMode = dockCreateMode;
   1069     }
   1070 
   1071     /**
   1072      * Update the current values in this ActivityOptions from those supplied
   1073      * in <var>otherOptions</var>.  Any values
   1074      * defined in <var>otherOptions</var> replace those in the base options.
   1075      */
   1076     public void update(ActivityOptions otherOptions) {
   1077         if (otherOptions.mPackageName != null) {
   1078             mPackageName = otherOptions.mPackageName;
   1079         }
   1080         mUsageTimeReport = otherOptions.mUsageTimeReport;
   1081         mTransitionReceiver = null;
   1082         mSharedElementNames = null;
   1083         mIsReturning = false;
   1084         mResultData = null;
   1085         mResultCode = 0;
   1086         mExitCoordinatorIndex = 0;
   1087         mAnimationType = otherOptions.mAnimationType;
   1088         switch (otherOptions.mAnimationType) {
   1089             case ANIM_CUSTOM:
   1090                 mCustomEnterResId = otherOptions.mCustomEnterResId;
   1091                 mCustomExitResId = otherOptions.mCustomExitResId;
   1092                 mThumbnail = null;
   1093                 if (mAnimationStartedListener != null) {
   1094                     try {
   1095                         mAnimationStartedListener.sendResult(null);
   1096                     } catch (RemoteException e) {
   1097                     }
   1098                 }
   1099                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
   1100                 break;
   1101             case ANIM_CUSTOM_IN_PLACE:
   1102                 mCustomInPlaceResId = otherOptions.mCustomInPlaceResId;
   1103                 break;
   1104             case ANIM_SCALE_UP:
   1105                 mStartX = otherOptions.mStartX;
   1106                 mStartY = otherOptions.mStartY;
   1107                 mWidth = otherOptions.mWidth;
   1108                 mHeight = otherOptions.mHeight;
   1109                 if (mAnimationStartedListener != null) {
   1110                     try {
   1111                         mAnimationStartedListener.sendResult(null);
   1112                     } catch (RemoteException e) {
   1113                     }
   1114                 }
   1115                 mAnimationStartedListener = null;
   1116                 break;
   1117             case ANIM_THUMBNAIL_SCALE_UP:
   1118             case ANIM_THUMBNAIL_SCALE_DOWN:
   1119             case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
   1120             case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
   1121                 mThumbnail = otherOptions.mThumbnail;
   1122                 mStartX = otherOptions.mStartX;
   1123                 mStartY = otherOptions.mStartY;
   1124                 mWidth = otherOptions.mWidth;
   1125                 mHeight = otherOptions.mHeight;
   1126                 if (mAnimationStartedListener != null) {
   1127                     try {
   1128                         mAnimationStartedListener.sendResult(null);
   1129                     } catch (RemoteException e) {
   1130                     }
   1131                 }
   1132                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
   1133                 break;
   1134             case ANIM_SCENE_TRANSITION:
   1135                 mTransitionReceiver = otherOptions.mTransitionReceiver;
   1136                 mSharedElementNames = otherOptions.mSharedElementNames;
   1137                 mIsReturning = otherOptions.mIsReturning;
   1138                 mThumbnail = null;
   1139                 mAnimationStartedListener = null;
   1140                 mResultData = otherOptions.mResultData;
   1141                 mResultCode = otherOptions.mResultCode;
   1142                 mExitCoordinatorIndex = otherOptions.mExitCoordinatorIndex;
   1143                 break;
   1144         }
   1145         mAnimSpecs = otherOptions.mAnimSpecs;
   1146         mAnimationFinishedListener = otherOptions.mAnimationFinishedListener;
   1147     }
   1148 
   1149     /**
   1150      * Returns the created options as a Bundle, which can be passed to
   1151      * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
   1152      * Context.startActivity(Intent, Bundle)} and related methods.
   1153      * Note that the returned Bundle is still owned by the ActivityOptions
   1154      * object; you must not modify it, but can supply it to the startActivity
   1155      * methods that take an options Bundle.
   1156      */
   1157     public Bundle toBundle() {
   1158         if (mAnimationType == ANIM_DEFAULT) {
   1159             return null;
   1160         }
   1161         Bundle b = new Bundle();
   1162         if (mPackageName != null) {
   1163             b.putString(KEY_PACKAGE_NAME, mPackageName);
   1164         }
   1165         if (mLaunchBounds != null) {
   1166             b.putParcelable(KEY_LAUNCH_BOUNDS, mLaunchBounds);
   1167         }
   1168         b.putInt(KEY_ANIM_TYPE, mAnimationType);
   1169         if (mUsageTimeReport != null) {
   1170             b.putParcelable(KEY_USAGE_TIME_REPORT, mUsageTimeReport);
   1171         }
   1172         switch (mAnimationType) {
   1173             case ANIM_CUSTOM:
   1174                 b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
   1175                 b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
   1176                 b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
   1177                         != null ? mAnimationStartedListener.asBinder() : null);
   1178                 break;
   1179             case ANIM_CUSTOM_IN_PLACE:
   1180                 b.putInt(KEY_ANIM_IN_PLACE_RES_ID, mCustomInPlaceResId);
   1181                 break;
   1182             case ANIM_SCALE_UP:
   1183             case ANIM_CLIP_REVEAL:
   1184                 b.putInt(KEY_ANIM_START_X, mStartX);
   1185                 b.putInt(KEY_ANIM_START_Y, mStartY);
   1186                 b.putInt(KEY_ANIM_WIDTH, mWidth);
   1187                 b.putInt(KEY_ANIM_HEIGHT, mHeight);
   1188                 break;
   1189             case ANIM_THUMBNAIL_SCALE_UP:
   1190             case ANIM_THUMBNAIL_SCALE_DOWN:
   1191             case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
   1192             case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
   1193                 b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
   1194                 b.putInt(KEY_ANIM_START_X, mStartX);
   1195                 b.putInt(KEY_ANIM_START_Y, mStartY);
   1196                 b.putInt(KEY_ANIM_WIDTH, mWidth);
   1197                 b.putInt(KEY_ANIM_HEIGHT, mHeight);
   1198                 b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
   1199                         != null ? mAnimationStartedListener.asBinder() : null);
   1200                 break;
   1201             case ANIM_SCENE_TRANSITION:
   1202                 if (mTransitionReceiver != null) {
   1203                     b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mTransitionReceiver);
   1204                 }
   1205                 b.putBoolean(KEY_TRANSITION_IS_RETURNING, mIsReturning);
   1206                 b.putStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS, mSharedElementNames);
   1207                 b.putParcelable(KEY_RESULT_DATA, mResultData);
   1208                 b.putInt(KEY_RESULT_CODE, mResultCode);
   1209                 b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
   1210                 break;
   1211         }
   1212         b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId);
   1213         b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
   1214         b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
   1215         b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode);
   1216         if (mAnimSpecs != null) {
   1217             b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
   1218         }
   1219         if (mAnimationFinishedListener != null) {
   1220             b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder());
   1221         }
   1222         b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
   1223 
   1224         return b;
   1225     }
   1226 
   1227     /**
   1228      * Ask the the system track that time the user spends in the app being launched, and
   1229      * report it back once done.  The report will be sent to the given receiver, with
   1230      * the extras {@link #EXTRA_USAGE_TIME_REPORT} and {@link #EXTRA_USAGE_TIME_REPORT_PACKAGES}
   1231      * filled in.
   1232      *
   1233      * <p>The time interval tracked is from launching this activity until the user leaves
   1234      * that activity's flow.  They are considered to stay in the flow as long as
   1235      * new activities are being launched or returned to from the original flow,
   1236      * even if this crosses package or task boundaries.  For example, if the originator
   1237      * starts an activity to view an image, and while there the user selects to share,
   1238      * which launches their email app in a new task, and they complete the share, the
   1239      * time during that entire operation will be included until they finally hit back from
   1240      * the original image viewer activity.</p>
   1241      *
   1242      * <p>The user is considered to complete a flow once they switch to another
   1243      * activity that is not part of the tracked flow.  This may happen, for example, by
   1244      * using the notification shade, launcher, or recents to launch or switch to another
   1245      * app.  Simply going in to these navigation elements does not break the flow (although
   1246      * the launcher and recents stops time tracking of the session); it is the act of
   1247      * going somewhere else that completes the tracking.</p>
   1248      *
   1249      * @param receiver A broadcast receiver that willl receive the report.
   1250      */
   1251     public void requestUsageTimeReport(PendingIntent receiver) {
   1252         mUsageTimeReport = receiver;
   1253     }
   1254 
   1255     /**
   1256      * Return the filtered options only meant to be seen by the target activity itself
   1257      * @hide
   1258      */
   1259     public ActivityOptions forTargetActivity() {
   1260         if (mAnimationType == ANIM_SCENE_TRANSITION) {
   1261             final ActivityOptions result = new ActivityOptions();
   1262             result.update(this);
   1263             return result;
   1264         }
   1265 
   1266         return null;
   1267     }
   1268 
   1269     /**
   1270      * Returns the rotation animation set by {@link setRotationAnimationHint} or -1
   1271      * if unspecified.
   1272      * @hide
   1273      */
   1274     public int getRotationAnimationHint() {
   1275         return mRotationAnimationHint;
   1276     }
   1277 
   1278 
   1279     /**
   1280      * Set a rotation animation to be used if launching the activity
   1281      * triggers an orientation change, or -1 to clear. See
   1282      * {@link android.view.WindowManager.LayoutParams} for rotation
   1283      * animation values.
   1284      * @hide
   1285      */
   1286     public void setRotationAnimationHint(int hint) {
   1287         mRotationAnimationHint = hint;
   1288     }
   1289 
   1290     /** @hide */
   1291     @Override
   1292     public String toString() {
   1293         return "ActivityOptions(" + hashCode() + "), mPackageName=" + mPackageName
   1294                 + ", mAnimationType=" + mAnimationType + ", mStartX=" + mStartX + ", mStartY="
   1295                 + mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight;
   1296     }
   1297 
   1298     private static class HideWindowListener extends Transition.TransitionListenerAdapter
   1299         implements ExitTransitionCoordinator.HideSharedElementsCallback {
   1300         private final Window mWindow;
   1301         private final ExitTransitionCoordinator mExit;
   1302         private final boolean mWaitingForTransition;
   1303         private boolean mTransitionEnded;
   1304         private boolean mSharedElementHidden;
   1305         private ArrayList<View> mSharedElements;
   1306 
   1307         public HideWindowListener(Window window, ExitTransitionCoordinator exit) {
   1308             mWindow = window;
   1309             mExit = exit;
   1310             mSharedElements = new ArrayList<>(exit.mSharedElements);
   1311             Transition transition = mWindow.getExitTransition();
   1312             if (transition != null) {
   1313                 transition.addListener(this);
   1314                 mWaitingForTransition = true;
   1315             } else {
   1316                 mWaitingForTransition = false;
   1317             }
   1318             View decorView = mWindow.getDecorView();
   1319             if (decorView != null) {
   1320                 if (decorView.getTag(com.android.internal.R.id.cross_task_transition) != null) {
   1321                     throw new IllegalStateException(
   1322                             "Cannot start a transition while one is running");
   1323                 }
   1324                 decorView.setTagInternal(com.android.internal.R.id.cross_task_transition, exit);
   1325             }
   1326         }
   1327 
   1328         @Override
   1329         public void onTransitionEnd(Transition transition) {
   1330             mTransitionEnded = true;
   1331             hideWhenDone();
   1332             transition.removeListener(this);
   1333         }
   1334 
   1335         @Override
   1336         public void hideSharedElements() {
   1337             mSharedElementHidden = true;
   1338             hideWhenDone();
   1339         }
   1340 
   1341         private void hideWhenDone() {
   1342             if (mSharedElementHidden && (!mWaitingForTransition || mTransitionEnded)) {
   1343                 mExit.resetViews();
   1344                 int numSharedElements = mSharedElements.size();
   1345                 for (int i = 0; i < numSharedElements; i++) {
   1346                     View view = mSharedElements.get(i);
   1347                     view.requestLayout();
   1348                 }
   1349                 View decorView = mWindow.getDecorView();
   1350                 if (decorView != null) {
   1351                     decorView.setTagInternal(
   1352                             com.android.internal.R.id.cross_task_transition, null);
   1353                     decorView.setVisibility(View.GONE);
   1354                 }
   1355             }
   1356         }
   1357     }
   1358 }
   1359