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 */ makeCustomAnimation(Context context, int enterResId, int exitResId)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 makeCustomAnimation(Context context, int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener)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 */ makeCustomInPlaceAnimation(Context context, int animId)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 setOnAnimationStartedListener(final Handler handler, final OnAnimationStartedListener listener)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 { onAnimationStarted()435 void onAnimationStarted(); 436 } 437 setOnAnimationFinishedListener(final Handler handler, final OnAnimationFinishedListener listener)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 { onAnimationFinished()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 */ makeScaleUpAnimation(View source, int startX, int startY, int width, int height)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 */ makeClipRevealAnimation(View source, int startX, int startY, int width, int height)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 */ makeOpenCrossProfileAppsAnimation()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 */ makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY)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 */ makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener)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 makeThumbnailAnimation(View source, Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener, boolean scaleUp)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 makeMultiThumbFutureAspectScaleAnimation(Context context, Handler handler, IAppTransitionAnimationSpecsFuture specsFuture, OnAnimationStartedListener listener, boolean scaleUp)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 */ makeThumbnailAspectScaleDownAnimation(View source, Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight, Handler handler, OnAnimationStartedListener listener)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 makeAspectScaledThumbnailAnimation(View source, Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight, Handler handler, OnAnimationStartedListener listener, boolean scaleUp)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 */ makeThumbnailAspectScaleDownAnimation(View source, AppTransitionAnimationSpec[] specs, Handler handler, OnAnimationStartedListener onAnimationStartedListener, OnAnimationFinishedListener onAnimationFinishedListener)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 */ makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName)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 makeSceneTransitionAnimation(Activity activity, Pair<View, String>... sharedElements)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 startSharedElementAnimation(Window window, Pair<View, String>... sharedElements)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 */ stopSharedElementAnimation(Window window)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 makeSceneTransitionAnimation(Activity activity, Window window, ActivityOptions opts, SharedElementCallback callback, Pair<View, String>[] sharedElements)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 */ makeSceneTransitionAnimation(Activity activity, ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames, int resultCode, Intent resultData)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 */ makeTaskLaunchBehind()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 */ makeBasic()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 makeRemoteAnimation( RemoteAnimationAdapter remoteAnimationAdapter)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 */ getLaunchTaskBehind()879 public boolean getLaunchTaskBehind() { 880 return mAnimationType == ANIM_LAUNCH_TASK_BEHIND; 881 } 882 ActivityOptions()883 private ActivityOptions() { 884 } 885 886 /** @hide */ ActivityOptions(Bundle opts)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 */ setLaunchBounds(@ullable Rect screenSpacePixelRect)991 public ActivityOptions setLaunchBounds(@Nullable Rect screenSpacePixelRect) { 992 mLaunchBounds = screenSpacePixelRect != null ? new Rect(screenSpacePixelRect) : null; 993 return this; 994 } 995 996 /** @hide */ getPackageName()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 getLaunchBounds()1007 public Rect getLaunchBounds() { 1008 return mLaunchBounds; 1009 } 1010 1011 /** @hide */ getAnimationType()1012 public int getAnimationType() { 1013 return mAnimationType; 1014 } 1015 1016 /** @hide */ getCustomEnterResId()1017 public int getCustomEnterResId() { 1018 return mCustomEnterResId; 1019 } 1020 1021 /** @hide */ getCustomExitResId()1022 public int getCustomExitResId() { 1023 return mCustomExitResId; 1024 } 1025 1026 /** @hide */ getCustomInPlaceResId()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 */ getThumbnail()1037 public GraphicBuffer getThumbnail() { 1038 return mThumbnail != null ? mThumbnail.createGraphicBufferHandle() : null; 1039 } 1040 1041 /** @hide */ getStartX()1042 public int getStartX() { 1043 return mStartX; 1044 } 1045 1046 /** @hide */ getStartY()1047 public int getStartY() { 1048 return mStartY; 1049 } 1050 1051 /** @hide */ getWidth()1052 public int getWidth() { 1053 return mWidth; 1054 } 1055 1056 /** @hide */ getHeight()1057 public int getHeight() { 1058 return mHeight; 1059 } 1060 1061 /** @hide */ getOnAnimationStartListener()1062 public IRemoteCallback getOnAnimationStartListener() { 1063 return mAnimationStartedListener; 1064 } 1065 1066 /** @hide */ getAnimationFinishedListener()1067 public IRemoteCallback getAnimationFinishedListener() { 1068 return mAnimationFinishedListener; 1069 } 1070 1071 /** @hide */ getExitCoordinatorKey()1072 public int getExitCoordinatorKey() { return mExitCoordinatorIndex; } 1073 1074 /** @hide */ abort()1075 public void abort() { 1076 if (mAnimationStartedListener != null) { 1077 try { 1078 mAnimationStartedListener.sendResult(null); 1079 } catch (RemoteException e) { 1080 } 1081 } 1082 } 1083 1084 /** @hide */ isReturning()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 */ isCrossTask()1095 boolean isCrossTask() { 1096 return mExitCoordinatorIndex < 0; 1097 } 1098 1099 /** @hide */ getSharedElementNames()1100 public ArrayList<String> getSharedElementNames() { 1101 return mSharedElementNames; 1102 } 1103 1104 /** @hide */ getResultReceiver()1105 public ResultReceiver getResultReceiver() { return mTransitionReceiver; } 1106 1107 /** @hide */ getResultCode()1108 public int getResultCode() { return mResultCode; } 1109 1110 /** @hide */ getResultData()1111 public Intent getResultData() { return mResultData; } 1112 1113 /** @hide */ getUsageTimeReport()1114 public PendingIntent getUsageTimeReport() { 1115 return mUsageTimeReport; 1116 } 1117 1118 /** @hide */ getAnimSpecs()1119 public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; } 1120 1121 /** @hide */ getSpecsFuture()1122 public IAppTransitionAnimationSpecsFuture getSpecsFuture() { 1123 return mSpecsFuture; 1124 } 1125 1126 /** @hide */ getRemoteAnimationAdapter()1127 public RemoteAnimationAdapter getRemoteAnimationAdapter() { 1128 return mRemoteAnimationAdapter; 1129 } 1130 1131 /** @hide */ setRemoteAnimationAdapter(RemoteAnimationAdapter remoteAnimationAdapter)1132 public void setRemoteAnimationAdapter(RemoteAnimationAdapter remoteAnimationAdapter) { 1133 mRemoteAnimationAdapter = remoteAnimationAdapter; 1134 } 1135 1136 /** @hide */ fromBundle(Bundle bOptions)1137 public static ActivityOptions fromBundle(Bundle bOptions) { 1138 return bOptions != null ? new ActivityOptions(bOptions) : null; 1139 } 1140 1141 /** @hide */ abort(ActivityOptions options)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 */ getLockTaskMode()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 */ setLockTaskEnabled(boolean lockTaskMode)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 */ getLaunchDisplayId()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 */ setLaunchDisplayId(int launchDisplayId)1201 public ActivityOptions setLaunchDisplayId(int launchDisplayId) { 1202 mLaunchDisplayId = launchDisplayId; 1203 return this; 1204 } 1205 1206 /** @hide */ getLaunchWindowingMode()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 setLaunchWindowingMode(int windowingMode)1222 public void setLaunchWindowingMode(int windowingMode) { 1223 mLaunchWindowingMode = windowingMode; 1224 } 1225 1226 /** @hide */ getLaunchActivityType()1227 public int getLaunchActivityType() { 1228 return mLaunchActivityType; 1229 } 1230 1231 /** @hide */ 1232 @TestApi setLaunchActivityType(int activityType)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 setLaunchTaskId(int taskId)1242 public void setLaunchTaskId(int taskId) { 1243 mLaunchTaskId = taskId; 1244 } 1245 1246 /** 1247 * @hide 1248 */ getLaunchTaskId()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 */ setPendingIntentLaunchFlags(@ndroid.content.Intent.Flags int flags)1258 public void setPendingIntentLaunchFlags(@android.content.Intent.Flags int flags) { 1259 mPendingIntentLaunchFlags = flags; 1260 } 1261 1262 /** 1263 * @hide 1264 */ getPendingIntentLaunchFlags()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 setTaskOverlay(boolean taskOverlay, boolean canResume)1276 public void setTaskOverlay(boolean taskOverlay, boolean canResume) { 1277 mTaskOverlay = taskOverlay; 1278 mTaskOverlayCanResume = canResume; 1279 } 1280 1281 /** 1282 * @hide 1283 */ getTaskOverlay()1284 public boolean getTaskOverlay() { 1285 return mTaskOverlay; 1286 } 1287 1288 /** 1289 * @hide 1290 */ canTaskOverlayResume()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 */ setAvoidMoveToFront()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 */ getAvoidMoveToFront()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 */ setFreezeRecentTasksReordering()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 */ freezeRecentTasksReordering()1328 public boolean freezeRecentTasksReordering() { 1329 return mFreezeRecentTasksReordering; 1330 } 1331 1332 /** @hide */ getSplitScreenCreateMode()1333 public int getSplitScreenCreateMode() { 1334 return mSplitScreenCreateMode; 1335 } 1336 1337 /** @hide */ 1338 @UnsupportedAppUsage setSplitScreenCreateMode(int splitScreenCreateMode)1339 public void setSplitScreenCreateMode(int splitScreenCreateMode) { 1340 mSplitScreenCreateMode = splitScreenCreateMode; 1341 } 1342 1343 /** @hide */ setDisallowEnterPictureInPictureWhileLaunching(boolean disallow)1344 public void setDisallowEnterPictureInPictureWhileLaunching(boolean disallow) { 1345 mDisallowEnterPictureInPictureWhileLaunching = disallow; 1346 } 1347 1348 /** @hide */ disallowEnterPictureInPictureWhileLaunching()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 */ update(ActivityOptions otherOptions)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 */ toBundle()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 */ requestUsageTimeReport(PendingIntent receiver)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 */ forTargetActivity()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 */ getRotationAnimationHint()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 */ setRotationAnimationHint(int hint)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 */ popAppVerificationBundle()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 */ setAppVerificationBundle(Bundle bundle)1642 public ActivityOptions setAppVerificationBundle(Bundle bundle) { 1643 mAppVerificationBundle = bundle; 1644 return this; 1645 1646 } 1647 1648 /** @hide */ 1649 @Override toString()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 HideWindowListener(Window window, ExitTransitionCoordinator exit)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 onTransitionEnd(Transition transition)1687 public void onTransitionEnd(Transition transition) { 1688 mTransitionEnded = true; 1689 hideWhenDone(); 1690 transition.removeListener(this); 1691 } 1692 1693 @Override hideSharedElements()1694 public void hideSharedElements() { 1695 mSharedElementHidden = true; 1696 hideWhenDone(); 1697 } 1698 hideWhenDone()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