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