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