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 */ makeCustomAnimation(Context context, int enterResId, int exitResId)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 */ makeCustomAnimation(Context context, int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener)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 */ makeCustomInPlaceAnimation(Context context, int animId)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 setOnAnimationStartedListener(final Handler handler, final OnAnimationStartedListener listener)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 { onAnimationStarted()417 void onAnimationStarted(); 418 } 419 setOnAnimationFinishedListener(final Handler handler, final OnAnimationFinishedListener listener)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 { onAnimationFinished()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 */ makeScaleUpAnimation(View source, int startX, int startY, int width, int height)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 */ makeClipRevealAnimation(View source, int startX, int startY, int width, int height)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 */ makeOpenCrossProfileAppsAnimation()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 */ makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY)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 */ makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener)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 makeThumbnailAnimation(View source, Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener, boolean scaleUp)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 */ makeMultiThumbFutureAspectScaleAnimation(Context context, Handler handler, IAppTransitionAnimationSpecsFuture specsFuture, OnAnimationStartedListener listener, boolean scaleUp)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 */ makeThumbnailAspectScaleDownAnimation(View source, Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight, Handler handler, OnAnimationStartedListener listener)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 makeAspectScaledThumbnailAnimation(View source, Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight, Handler handler, OnAnimationStartedListener listener, boolean scaleUp)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 */ makeThumbnailAspectScaleDownAnimation(View source, AppTransitionAnimationSpec[] specs, Handler handler, OnAnimationStartedListener onAnimationStartedListener, OnAnimationFinishedListener onAnimationFinishedListener)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 */ makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName)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 makeSceneTransitionAnimation(Activity activity, Pair<View, String>... sharedElements)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 startSharedElementAnimation(Window window, Pair<View, String>... sharedElements)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 */ stopSharedElementAnimation(Window window)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 makeSceneTransitionAnimation(Activity activity, Window window, ActivityOptions opts, SharedElementCallback callback, Pair<View, String>[] sharedElements)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 */ makeSceneTransitionAnimation(Activity activity, ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames, int resultCode, Intent resultData)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 */ makeTaskLaunchBehind()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 */ makeBasic()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) makeRemoteAnimation( RemoteAnimationAdapter remoteAnimationAdapter)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 */ getLaunchTaskBehind()859 public boolean getLaunchTaskBehind() { 860 return mAnimationType == ANIM_LAUNCH_TASK_BEHIND; 861 } 862 ActivityOptions()863 private ActivityOptions() { 864 } 865 866 /** @hide */ ActivityOptions(Bundle opts)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 */ setLaunchBounds(@ullable Rect screenSpacePixelRect)968 public ActivityOptions setLaunchBounds(@Nullable Rect screenSpacePixelRect) { 969 mLaunchBounds = screenSpacePixelRect != null ? new Rect(screenSpacePixelRect) : null; 970 return this; 971 } 972 973 /** @hide */ getPackageName()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 getLaunchBounds()984 public Rect getLaunchBounds() { 985 return mLaunchBounds; 986 } 987 988 /** @hide */ getAnimationType()989 public int getAnimationType() { 990 return mAnimationType; 991 } 992 993 /** @hide */ getCustomEnterResId()994 public int getCustomEnterResId() { 995 return mCustomEnterResId; 996 } 997 998 /** @hide */ getCustomExitResId()999 public int getCustomExitResId() { 1000 return mCustomExitResId; 1001 } 1002 1003 /** @hide */ getCustomInPlaceResId()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 */ getThumbnail()1014 public GraphicBuffer getThumbnail() { 1015 return mThumbnail != null ? mThumbnail.createGraphicBufferHandle() : null; 1016 } 1017 1018 /** @hide */ getStartX()1019 public int getStartX() { 1020 return mStartX; 1021 } 1022 1023 /** @hide */ getStartY()1024 public int getStartY() { 1025 return mStartY; 1026 } 1027 1028 /** @hide */ getWidth()1029 public int getWidth() { 1030 return mWidth; 1031 } 1032 1033 /** @hide */ getHeight()1034 public int getHeight() { 1035 return mHeight; 1036 } 1037 1038 /** @hide */ getOnAnimationStartListener()1039 public IRemoteCallback getOnAnimationStartListener() { 1040 return mAnimationStartedListener; 1041 } 1042 1043 /** @hide */ getAnimationFinishedListener()1044 public IRemoteCallback getAnimationFinishedListener() { 1045 return mAnimationFinishedListener; 1046 } 1047 1048 /** @hide */ getExitCoordinatorKey()1049 public int getExitCoordinatorKey() { return mExitCoordinatorIndex; } 1050 1051 /** @hide */ abort()1052 public void abort() { 1053 if (mAnimationStartedListener != null) { 1054 try { 1055 mAnimationStartedListener.sendResult(null); 1056 } catch (RemoteException e) { 1057 } 1058 } 1059 } 1060 1061 /** @hide */ isReturning()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 */ isCrossTask()1072 boolean isCrossTask() { 1073 return mExitCoordinatorIndex < 0; 1074 } 1075 1076 /** @hide */ getSharedElementNames()1077 public ArrayList<String> getSharedElementNames() { 1078 return mSharedElementNames; 1079 } 1080 1081 /** @hide */ getResultReceiver()1082 public ResultReceiver getResultReceiver() { return mTransitionReceiver; } 1083 1084 /** @hide */ getResultCode()1085 public int getResultCode() { return mResultCode; } 1086 1087 /** @hide */ getResultData()1088 public Intent getResultData() { return mResultData; } 1089 1090 /** @hide */ getUsageTimeReport()1091 public PendingIntent getUsageTimeReport() { 1092 return mUsageTimeReport; 1093 } 1094 1095 /** @hide */ getAnimSpecs()1096 public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; } 1097 1098 /** @hide */ getSpecsFuture()1099 public IAppTransitionAnimationSpecsFuture getSpecsFuture() { 1100 return mSpecsFuture; 1101 } 1102 1103 /** @hide */ getRemoteAnimationAdapter()1104 public RemoteAnimationAdapter getRemoteAnimationAdapter() { 1105 return mRemoteAnimationAdapter; 1106 } 1107 1108 /** @hide */ setRemoteAnimationAdapter(RemoteAnimationAdapter remoteAnimationAdapter)1109 public void setRemoteAnimationAdapter(RemoteAnimationAdapter remoteAnimationAdapter) { 1110 mRemoteAnimationAdapter = remoteAnimationAdapter; 1111 } 1112 1113 /** @hide */ fromBundle(Bundle bOptions)1114 public static ActivityOptions fromBundle(Bundle bOptions) { 1115 return bOptions != null ? new ActivityOptions(bOptions) : null; 1116 } 1117 1118 /** @hide */ abort(ActivityOptions options)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 */ getLockTaskMode()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 */ setLockTaskEnabled(boolean lockTaskMode)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 */ getLaunchDisplayId()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 */ setLaunchDisplayId(int launchDisplayId)1178 public ActivityOptions setLaunchDisplayId(int launchDisplayId) { 1179 mLaunchDisplayId = launchDisplayId; 1180 return this; 1181 } 1182 1183 /** @hide */ getLaunchWindowingMode()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 setLaunchWindowingMode(int windowingMode)1199 public void setLaunchWindowingMode(int windowingMode) { 1200 mLaunchWindowingMode = windowingMode; 1201 } 1202 1203 /** @hide */ getLaunchActivityType()1204 public int getLaunchActivityType() { 1205 return mLaunchActivityType; 1206 } 1207 1208 /** @hide */ 1209 @TestApi setLaunchActivityType(int activityType)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 setLaunchTaskId(int taskId)1219 public void setLaunchTaskId(int taskId) { 1220 mLaunchTaskId = taskId; 1221 } 1222 1223 /** 1224 * @hide 1225 */ getLaunchTaskId()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 setTaskOverlay(boolean taskOverlay, boolean canResume)1237 public void setTaskOverlay(boolean taskOverlay, boolean canResume) { 1238 mTaskOverlay = taskOverlay; 1239 mTaskOverlayCanResume = canResume; 1240 } 1241 1242 /** 1243 * @hide 1244 */ getTaskOverlay()1245 public boolean getTaskOverlay() { 1246 return mTaskOverlay; 1247 } 1248 1249 /** 1250 * @hide 1251 */ canTaskOverlayResume()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 */ setAvoidMoveToFront()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 */ getAvoidMoveToFront()1271 public boolean getAvoidMoveToFront() { 1272 return mAvoidMoveToFront; 1273 } 1274 1275 /** @hide */ getSplitScreenCreateMode()1276 public int getSplitScreenCreateMode() { 1277 return mSplitScreenCreateMode; 1278 } 1279 1280 /** @hide */ setSplitScreenCreateMode(int splitScreenCreateMode)1281 public void setSplitScreenCreateMode(int splitScreenCreateMode) { 1282 mSplitScreenCreateMode = splitScreenCreateMode; 1283 } 1284 1285 /** @hide */ setDisallowEnterPictureInPictureWhileLaunching(boolean disallow)1286 public void setDisallowEnterPictureInPictureWhileLaunching(boolean disallow) { 1287 mDisallowEnterPictureInPictureWhileLaunching = disallow; 1288 } 1289 1290 /** @hide */ disallowEnterPictureInPictureWhileLaunching()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 */ update(ActivityOptions otherOptions)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 */ toBundle()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 */ requestUsageTimeReport(PendingIntent receiver)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 */ forTargetActivity()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 */ getRotationAnimationHint()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 */ setRotationAnimationHint(int hint)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 */ popAppVerificationBundle()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 */ setAppVerificationBundle(Bundle bundle)1556 public ActivityOptions setAppVerificationBundle(Bundle bundle) { 1557 mAppVerificationBundle = bundle; 1558 return this; 1559 1560 } 1561 1562 /** @hide */ 1563 @Override toString()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 HideWindowListener(Window window, ExitTransitionCoordinator exit)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 onTransitionEnd(Transition transition)1601 public void onTransitionEnd(Transition transition) { 1602 mTransitionEnded = true; 1603 hideWhenDone(); 1604 transition.removeListener(this); 1605 } 1606 1607 @Override hideSharedElements()1608 public void hideSharedElements() { 1609 mSharedElementHidden = true; 1610 hideWhenDone(); 1611 } 1612 hideWhenDone()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