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 */ 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 */ 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 */ 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 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 { 344 void onAnimationStarted(); 345 } 346 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 { 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 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 */ 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 */ 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 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 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 */ 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 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 */ 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 */ 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 */ 784 public static ActivityOptions makeBasic() { 785 final ActivityOptions opts = new ActivityOptions(); 786 return opts; 787 } 788 789 /** @hide */ 790 public boolean getLaunchTaskBehind() { 791 return mAnimationType == ANIM_LAUNCH_TASK_BEHIND; 792 } 793 794 private ActivityOptions() { 795 } 796 797 /** @hide */ 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 */ 881 public ActivityOptions setLaunchBounds(@Nullable Rect screenSpacePixelRect) { 882 mLaunchBounds = screenSpacePixelRect != null ? new Rect(screenSpacePixelRect) : null; 883 return this; 884 } 885 886 /** @hide */ 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 897 public Rect getLaunchBounds() { 898 return mLaunchBounds; 899 } 900 901 /** @hide */ 902 public int getAnimationType() { 903 return mAnimationType; 904 } 905 906 /** @hide */ 907 public int getCustomEnterResId() { 908 return mCustomEnterResId; 909 } 910 911 /** @hide */ 912 public int getCustomExitResId() { 913 return mCustomExitResId; 914 } 915 916 /** @hide */ 917 public int getCustomInPlaceResId() { 918 return mCustomInPlaceResId; 919 } 920 921 /** @hide */ 922 public Bitmap getThumbnail() { 923 return mThumbnail; 924 } 925 926 /** @hide */ 927 public int getStartX() { 928 return mStartX; 929 } 930 931 /** @hide */ 932 public int getStartY() { 933 return mStartY; 934 } 935 936 /** @hide */ 937 public int getWidth() { 938 return mWidth; 939 } 940 941 /** @hide */ 942 public int getHeight() { 943 return mHeight; 944 } 945 946 /** @hide */ 947 public IRemoteCallback getOnAnimationStartListener() { 948 return mAnimationStartedListener; 949 } 950 951 /** @hide */ 952 public IRemoteCallback getAnimationFinishedListener() { 953 return mAnimationFinishedListener; 954 } 955 956 /** @hide */ 957 public int getExitCoordinatorKey() { return mExitCoordinatorIndex; } 958 959 /** @hide */ 960 public void abort() { 961 if (mAnimationStartedListener != null) { 962 try { 963 mAnimationStartedListener.sendResult(null); 964 } catch (RemoteException e) { 965 } 966 } 967 } 968 969 /** @hide */ 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 */ 980 boolean isCrossTask() { 981 return mExitCoordinatorIndex < 0; 982 } 983 984 /** @hide */ 985 public ArrayList<String> getSharedElementNames() { 986 return mSharedElementNames; 987 } 988 989 /** @hide */ 990 public ResultReceiver getResultReceiver() { return mTransitionReceiver; } 991 992 /** @hide */ 993 public int getResultCode() { return mResultCode; } 994 995 /** @hide */ 996 public Intent getResultData() { return mResultData; } 997 998 /** @hide */ 999 public PendingIntent getUsageTimeReport() { 1000 return mUsageTimeReport; 1001 } 1002 1003 /** @hide */ 1004 public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; } 1005 1006 /** @hide */ 1007 public static ActivityOptions fromBundle(Bundle bOptions) { 1008 return bOptions != null ? new ActivityOptions(bOptions) : null; 1009 } 1010 1011 /** @hide */ 1012 public static void abort(ActivityOptions options) { 1013 if (options != null) { 1014 options.abort(); 1015 } 1016 } 1017 1018 /** @hide */ 1019 public int getLaunchStackId() { 1020 return mLaunchStackId; 1021 } 1022 1023 /** @hide */ 1024 @TestApi 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 */ 1033 public void setLaunchTaskId(int taskId) { 1034 mLaunchTaskId = taskId; 1035 } 1036 1037 /** 1038 * @hide 1039 */ 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 */ 1050 public void setTaskOverlay(boolean taskOverlay) { 1051 mTaskOverlay = taskOverlay; 1052 } 1053 1054 /** 1055 * @hide 1056 */ 1057 public boolean getTaskOverlay() { 1058 return mTaskOverlay; 1059 } 1060 1061 /** @hide */ 1062 public int getDockCreateMode() { 1063 return mDockCreateMode; 1064 } 1065 1066 /** @hide */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 1286 public void setRotationAnimationHint(int hint) { 1287 mRotationAnimationHint = hint; 1288 } 1289 1290 /** @hide */ 1291 @Override 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 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 1329 public void onTransitionEnd(Transition transition) { 1330 mTransitionEnded = true; 1331 hideWhenDone(); 1332 transition.removeListener(this); 1333 } 1334 1335 @Override 1336 public void hideSharedElements() { 1337 mSharedElementHidden = true; 1338 hideWhenDone(); 1339 } 1340 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