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