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