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