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