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