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