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 */ 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 */ 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 */ 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 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 { 371 void onAnimationStarted(); 372 } 373 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 { 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 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 */ 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 */ 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 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 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 */ 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 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 */ 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 */ 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 */ 780 public static ActivityOptions makeBasic() { 781 final ActivityOptions opts = new ActivityOptions(); 782 return opts; 783 } 784 785 /** @hide */ 786 public boolean getLaunchTaskBehind() { 787 return mAnimationType == ANIM_LAUNCH_TASK_BEHIND; 788 } 789 790 private ActivityOptions() { 791 } 792 793 /** @hide */ 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 */ 888 public ActivityOptions setLaunchBounds(@Nullable Rect screenSpacePixelRect) { 889 mLaunchBounds = screenSpacePixelRect != null ? new Rect(screenSpacePixelRect) : null; 890 return this; 891 } 892 893 /** @hide */ 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 904 public Rect getLaunchBounds() { 905 return mLaunchBounds; 906 } 907 908 /** @hide */ 909 public int getAnimationType() { 910 return mAnimationType; 911 } 912 913 /** @hide */ 914 public int getCustomEnterResId() { 915 return mCustomEnterResId; 916 } 917 918 /** @hide */ 919 public int getCustomExitResId() { 920 return mCustomExitResId; 921 } 922 923 /** @hide */ 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 */ 934 public GraphicBuffer getThumbnail() { 935 return mThumbnail != null ? mThumbnail.createGraphicBufferHandle() : null; 936 } 937 938 /** @hide */ 939 public int getStartX() { 940 return mStartX; 941 } 942 943 /** @hide */ 944 public int getStartY() { 945 return mStartY; 946 } 947 948 /** @hide */ 949 public int getWidth() { 950 return mWidth; 951 } 952 953 /** @hide */ 954 public int getHeight() { 955 return mHeight; 956 } 957 958 /** @hide */ 959 public IRemoteCallback getOnAnimationStartListener() { 960 return mAnimationStartedListener; 961 } 962 963 /** @hide */ 964 public IRemoteCallback getAnimationFinishedListener() { 965 return mAnimationFinishedListener; 966 } 967 968 /** @hide */ 969 public int getExitCoordinatorKey() { return mExitCoordinatorIndex; } 970 971 /** @hide */ 972 public void abort() { 973 if (mAnimationStartedListener != null) { 974 try { 975 mAnimationStartedListener.sendResult(null); 976 } catch (RemoteException e) { 977 } 978 } 979 } 980 981 /** @hide */ 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 */ 992 boolean isCrossTask() { 993 return mExitCoordinatorIndex < 0; 994 } 995 996 /** @hide */ 997 public ArrayList<String> getSharedElementNames() { 998 return mSharedElementNames; 999 } 1000 1001 /** @hide */ 1002 public ResultReceiver getResultReceiver() { return mTransitionReceiver; } 1003 1004 /** @hide */ 1005 public int getResultCode() { return mResultCode; } 1006 1007 /** @hide */ 1008 public Intent getResultData() { return mResultData; } 1009 1010 /** @hide */ 1011 public PendingIntent getUsageTimeReport() { 1012 return mUsageTimeReport; 1013 } 1014 1015 /** @hide */ 1016 public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; } 1017 1018 /** @hide */ 1019 public IAppTransitionAnimationSpecsFuture getSpecsFuture() { 1020 return mSpecsFuture; 1021 } 1022 1023 /** @hide */ 1024 public static ActivityOptions fromBundle(Bundle bOptions) { 1025 return bOptions != null ? new ActivityOptions(bOptions) : null; 1026 } 1027 1028 /** @hide */ 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 */ 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 */ 1056 public ActivityOptions setLaunchDisplayId(int launchDisplayId) { 1057 mLaunchDisplayId = launchDisplayId; 1058 return this; 1059 } 1060 1061 /** @hide */ 1062 public int getLaunchStackId() { 1063 return mLaunchStackId; 1064 } 1065 1066 /** @hide */ 1067 @TestApi 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 1077 public void setLaunchTaskId(int taskId) { 1078 mLaunchTaskId = taskId; 1079 } 1080 1081 /** 1082 * @hide 1083 */ 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 1095 public void setTaskOverlay(boolean taskOverlay, boolean canResume) { 1096 mTaskOverlay = taskOverlay; 1097 mTaskOverlayCanResume = canResume; 1098 } 1099 1100 /** 1101 * @hide 1102 */ 1103 public boolean getTaskOverlay() { 1104 return mTaskOverlay; 1105 } 1106 1107 /** 1108 * @hide 1109 */ 1110 public boolean canTaskOverlayResume() { 1111 return mTaskOverlayCanResume; 1112 } 1113 1114 /** @hide */ 1115 public int getDockCreateMode() { 1116 return mDockCreateMode; 1117 } 1118 1119 /** @hide */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 1376 public ActivityOptions setAppVerificationBundle(Bundle bundle) { 1377 mAppVerificationBundle = bundle; 1378 return this; 1379 1380 } 1381 1382 /** @hide */ 1383 @Override 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 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 1421 public void onTransitionEnd(Transition transition) { 1422 mTransitionEnded = true; 1423 hideWhenDone(); 1424 transition.removeListener(this); 1425 } 1426 1427 @Override 1428 public void hideSharedElements() { 1429 mSharedElementHidden = true; 1430 hideWhenDone(); 1431 } 1432 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