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