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