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