ActivityOptions.java revision 7f1bdd9f9180574c8b6b98cefe3c542b92477295
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 @SafeVarargs 625 public static ActivityOptions makeSceneTransitionAnimation(Activity activity, 626 Pair<View, String>... sharedElements) { 627 ActivityOptions opts = new ActivityOptions(); 628 if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) { 629 opts.mAnimationType = ANIM_DEFAULT; 630 return opts; 631 } 632 opts.mAnimationType = ANIM_SCENE_TRANSITION; 633 634 ArrayList<String> names = new ArrayList<String>(); 635 ArrayList<View> views = new ArrayList<View>(); 636 637 if (sharedElements != null) { 638 for (int i = 0; i < sharedElements.length; i++) { 639 Pair<View, String> sharedElement = sharedElements[i]; 640 String sharedElementName = sharedElement.second; 641 if (sharedElementName == null) { 642 throw new IllegalArgumentException("Shared element name must not be null"); 643 } 644 names.add(sharedElementName); 645 View view = sharedElement.first; 646 if (view == null) { 647 throw new IllegalArgumentException("Shared element must not be null"); 648 } 649 views.add(sharedElement.first); 650 } 651 } 652 653 ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, names, names, 654 views, false); 655 opts.mTransitionReceiver = exit; 656 opts.mSharedElementNames = names; 657 opts.mIsReturning = false; 658 opts.mExitCoordinatorIndex = 659 activity.mActivityTransitionState.addExitTransitionCoordinator(exit); 660 return opts; 661 } 662 663 /** @hide */ 664 public static ActivityOptions makeSceneTransitionAnimation(Activity activity, 665 ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames, 666 int resultCode, Intent resultData) { 667 ActivityOptions opts = new ActivityOptions(); 668 opts.mAnimationType = ANIM_SCENE_TRANSITION; 669 opts.mSharedElementNames = sharedElementNames; 670 opts.mTransitionReceiver = exitCoordinator; 671 opts.mIsReturning = true; 672 opts.mResultCode = resultCode; 673 opts.mResultData = resultData; 674 opts.mExitCoordinatorIndex = 675 activity.mActivityTransitionState.addExitTransitionCoordinator(exitCoordinator); 676 return opts; 677 } 678 679 /** 680 * If set along with Intent.FLAG_ACTIVITY_NEW_DOCUMENT then the task being launched will not be 681 * presented to the user but will instead be only available through the recents task list. 682 * In addition, the new task wil be affiliated with the launching activity's task. 683 * Affiliated tasks are grouped together in the recents task list. 684 * 685 * <p>This behavior is not supported for activities with {@link 686 * android.R.styleable#AndroidManifestActivity_launchMode launchMode} values of 687 * <code>singleInstance</code> or <code>singleTask</code>. 688 */ 689 public static ActivityOptions makeTaskLaunchBehind() { 690 final ActivityOptions opts = new ActivityOptions(); 691 opts.mAnimationType = ANIM_LAUNCH_TASK_BEHIND; 692 return opts; 693 } 694 695 /** 696 * Create a basic ActivityOptions that has no special animation associated with it. 697 * Other options can still be set. 698 */ 699 public static ActivityOptions makeBasic() { 700 final ActivityOptions opts = new ActivityOptions(); 701 return opts; 702 } 703 704 /** @hide */ 705 public boolean getLaunchTaskBehind() { 706 return mAnimationType == ANIM_LAUNCH_TASK_BEHIND; 707 } 708 709 private ActivityOptions() { 710 } 711 712 /** @hide */ 713 public ActivityOptions(Bundle opts) { 714 // If the remote side sent us bad parcelables, they won't get the 715 // results they want, which is their loss. 716 opts.setDefusable(true); 717 718 mPackageName = opts.getString(KEY_PACKAGE_NAME); 719 try { 720 mUsageTimeReport = opts.getParcelable(KEY_USAGE_TIME_REPORT); 721 } catch (RuntimeException e) { 722 Slog.w(TAG, e); 723 } 724 mLaunchBounds = opts.getParcelable(KEY_LAUNCH_BOUNDS); 725 mAnimationType = opts.getInt(KEY_ANIM_TYPE); 726 switch (mAnimationType) { 727 case ANIM_CUSTOM: 728 mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0); 729 mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0); 730 mAnimationStartedListener = IRemoteCallback.Stub.asInterface( 731 opts.getBinder(KEY_ANIM_START_LISTENER)); 732 break; 733 734 case ANIM_CUSTOM_IN_PLACE: 735 mCustomInPlaceResId = opts.getInt(KEY_ANIM_IN_PLACE_RES_ID, 0); 736 break; 737 738 case ANIM_SCALE_UP: 739 case ANIM_CLIP_REVEAL: 740 mStartX = opts.getInt(KEY_ANIM_START_X, 0); 741 mStartY = opts.getInt(KEY_ANIM_START_Y, 0); 742 mWidth = opts.getInt(KEY_ANIM_WIDTH, 0); 743 mHeight = opts.getInt(KEY_ANIM_HEIGHT, 0); 744 break; 745 746 case ANIM_THUMBNAIL_SCALE_UP: 747 case ANIM_THUMBNAIL_SCALE_DOWN: 748 case ANIM_THUMBNAIL_ASPECT_SCALE_UP: 749 case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN: 750 mThumbnail = (Bitmap) opts.getParcelable(KEY_ANIM_THUMBNAIL); 751 mStartX = opts.getInt(KEY_ANIM_START_X, 0); 752 mStartY = opts.getInt(KEY_ANIM_START_Y, 0); 753 mWidth = opts.getInt(KEY_ANIM_WIDTH, 0); 754 mHeight = opts.getInt(KEY_ANIM_HEIGHT, 0); 755 mAnimationStartedListener = IRemoteCallback.Stub.asInterface( 756 opts.getBinder(KEY_ANIM_START_LISTENER)); 757 break; 758 759 case ANIM_SCENE_TRANSITION: 760 mTransitionReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER); 761 mIsReturning = opts.getBoolean(KEY_TRANSITION_IS_RETURNING, false); 762 mSharedElementNames = opts.getStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS); 763 mResultData = opts.getParcelable(KEY_RESULT_DATA); 764 mResultCode = opts.getInt(KEY_RESULT_CODE); 765 mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX); 766 break; 767 } 768 mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID); 769 mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT); 770 if (opts.containsKey(KEY_ANIM_SPECS)) { 771 Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS); 772 mAnimSpecs = new AppTransitionAnimationSpec[specs.length]; 773 for (int i = specs.length - 1; i >= 0; i--) { 774 mAnimSpecs[i] = (AppTransitionAnimationSpec) specs[i]; 775 } 776 } 777 if (opts.containsKey(KEY_ANIMATION_FINISHED_LISTENER)) { 778 mAnimationFinishedListener = IRemoteCallback.Stub.asInterface( 779 opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER)); 780 } 781 } 782 783 /** 784 * Sets the bounds (window size) that the activity should be launched in. 785 * Rect position should be provided in pixels and in screen coordinates. 786 * Set to null explicitly for fullscreen. 787 * <p> 788 * <strong>NOTE:<strong/> This value is ignored on devices that don't have 789 * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or 790 * {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled. 791 * @param screenSpacePixelRect Launch bounds to use for the activity or null for fullscreen. 792 */ 793 public ActivityOptions setLaunchBounds(@Nullable Rect screenSpacePixelRect) { 794 mLaunchBounds = screenSpacePixelRect != null ? new Rect(screenSpacePixelRect) : null; 795 return this; 796 } 797 798 /** @hide */ 799 public String getPackageName() { 800 return mPackageName; 801 } 802 803 /** 804 * Returns the bounds that should be used to launch the activity. 805 * @see #setLaunchBounds(Rect) 806 * @return Bounds used to launch the activity. 807 */ 808 @Nullable 809 public Rect getLaunchBounds() { 810 return mLaunchBounds; 811 } 812 813 /** @hide */ 814 public int getAnimationType() { 815 return mAnimationType; 816 } 817 818 /** @hide */ 819 public int getCustomEnterResId() { 820 return mCustomEnterResId; 821 } 822 823 /** @hide */ 824 public int getCustomExitResId() { 825 return mCustomExitResId; 826 } 827 828 /** @hide */ 829 public int getCustomInPlaceResId() { 830 return mCustomInPlaceResId; 831 } 832 833 /** @hide */ 834 public Bitmap getThumbnail() { 835 return mThumbnail; 836 } 837 838 /** @hide */ 839 public int getStartX() { 840 return mStartX; 841 } 842 843 /** @hide */ 844 public int getStartY() { 845 return mStartY; 846 } 847 848 /** @hide */ 849 public int getWidth() { 850 return mWidth; 851 } 852 853 /** @hide */ 854 public int getHeight() { 855 return mHeight; 856 } 857 858 /** @hide */ 859 public IRemoteCallback getOnAnimationStartListener() { 860 return mAnimationStartedListener; 861 } 862 863 /** @hide */ 864 public IRemoteCallback getAnimationFinishedListener() { 865 return mAnimationFinishedListener; 866 } 867 868 /** @hide */ 869 public int getExitCoordinatorKey() { return mExitCoordinatorIndex; } 870 871 /** @hide */ 872 public void abort() { 873 if (mAnimationStartedListener != null) { 874 try { 875 mAnimationStartedListener.sendResult(null); 876 } catch (RemoteException e) { 877 } 878 } 879 } 880 881 /** @hide */ 882 public boolean isReturning() { 883 return mIsReturning; 884 } 885 886 /** @hide */ 887 public ArrayList<String> getSharedElementNames() { 888 return mSharedElementNames; 889 } 890 891 /** @hide */ 892 public ResultReceiver getResultReceiver() { return mTransitionReceiver; } 893 894 /** @hide */ 895 public int getResultCode() { return mResultCode; } 896 897 /** @hide */ 898 public Intent getResultData() { return mResultData; } 899 900 /** @hide */ 901 public PendingIntent getUsageTimeReport() { 902 return mUsageTimeReport; 903 } 904 905 /** @hide */ 906 public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; } 907 908 /** @hide */ 909 public static ActivityOptions fromBundle(Bundle bOptions) { 910 return bOptions != null ? new ActivityOptions(bOptions) : null; 911 } 912 913 /** @hide */ 914 public static void abort(ActivityOptions options) { 915 if (options != null) { 916 options.abort(); 917 } 918 } 919 920 /** @hide */ 921 public int getLaunchStackId() { 922 return mLaunchStackId; 923 } 924 925 /** @hide */ 926 public void setLaunchStackId(int launchStackId) { 927 mLaunchStackId = launchStackId; 928 } 929 930 /** @hide */ 931 public int getDockCreateMode() { 932 return mDockCreateMode; 933 } 934 935 /** @hide */ 936 public void setDockCreateMode(int dockCreateMode) { 937 mDockCreateMode = dockCreateMode; 938 } 939 940 /** 941 * Update the current values in this ActivityOptions from those supplied 942 * in <var>otherOptions</var>. Any values 943 * defined in <var>otherOptions</var> replace those in the base options. 944 */ 945 public void update(ActivityOptions otherOptions) { 946 if (otherOptions.mPackageName != null) { 947 mPackageName = otherOptions.mPackageName; 948 } 949 mUsageTimeReport = otherOptions.mUsageTimeReport; 950 mTransitionReceiver = null; 951 mSharedElementNames = null; 952 mIsReturning = false; 953 mResultData = null; 954 mResultCode = 0; 955 mExitCoordinatorIndex = 0; 956 mAnimationType = otherOptions.mAnimationType; 957 switch (otherOptions.mAnimationType) { 958 case ANIM_CUSTOM: 959 mCustomEnterResId = otherOptions.mCustomEnterResId; 960 mCustomExitResId = otherOptions.mCustomExitResId; 961 mThumbnail = null; 962 if (mAnimationStartedListener != null) { 963 try { 964 mAnimationStartedListener.sendResult(null); 965 } catch (RemoteException e) { 966 } 967 } 968 mAnimationStartedListener = otherOptions.mAnimationStartedListener; 969 break; 970 case ANIM_CUSTOM_IN_PLACE: 971 mCustomInPlaceResId = otherOptions.mCustomInPlaceResId; 972 break; 973 case ANIM_SCALE_UP: 974 mStartX = otherOptions.mStartX; 975 mStartY = otherOptions.mStartY; 976 mWidth = otherOptions.mWidth; 977 mHeight = otherOptions.mHeight; 978 if (mAnimationStartedListener != null) { 979 try { 980 mAnimationStartedListener.sendResult(null); 981 } catch (RemoteException e) { 982 } 983 } 984 mAnimationStartedListener = null; 985 break; 986 case ANIM_THUMBNAIL_SCALE_UP: 987 case ANIM_THUMBNAIL_SCALE_DOWN: 988 case ANIM_THUMBNAIL_ASPECT_SCALE_UP: 989 case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN: 990 mThumbnail = otherOptions.mThumbnail; 991 mStartX = otherOptions.mStartX; 992 mStartY = otherOptions.mStartY; 993 mWidth = otherOptions.mWidth; 994 mHeight = otherOptions.mHeight; 995 if (mAnimationStartedListener != null) { 996 try { 997 mAnimationStartedListener.sendResult(null); 998 } catch (RemoteException e) { 999 } 1000 } 1001 mAnimationStartedListener = otherOptions.mAnimationStartedListener; 1002 break; 1003 case ANIM_SCENE_TRANSITION: 1004 mTransitionReceiver = otherOptions.mTransitionReceiver; 1005 mSharedElementNames = otherOptions.mSharedElementNames; 1006 mIsReturning = otherOptions.mIsReturning; 1007 mThumbnail = null; 1008 mAnimationStartedListener = null; 1009 mResultData = otherOptions.mResultData; 1010 mResultCode = otherOptions.mResultCode; 1011 mExitCoordinatorIndex = otherOptions.mExitCoordinatorIndex; 1012 break; 1013 } 1014 mAnimSpecs = otherOptions.mAnimSpecs; 1015 mAnimationFinishedListener = otherOptions.mAnimationFinishedListener; 1016 } 1017 1018 /** 1019 * Returns the created options as a Bundle, which can be passed to 1020 * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle) 1021 * Context.startActivity(Intent, Bundle)} and related methods. 1022 * Note that the returned Bundle is still owned by the ActivityOptions 1023 * object; you must not modify it, but can supply it to the startActivity 1024 * methods that take an options Bundle. 1025 */ 1026 public Bundle toBundle() { 1027 if (mAnimationType == ANIM_DEFAULT) { 1028 return null; 1029 } 1030 Bundle b = new Bundle(); 1031 if (mPackageName != null) { 1032 b.putString(KEY_PACKAGE_NAME, mPackageName); 1033 } 1034 if (mLaunchBounds != null) { 1035 b.putParcelable(KEY_LAUNCH_BOUNDS, mLaunchBounds); 1036 } 1037 b.putInt(KEY_ANIM_TYPE, mAnimationType); 1038 if (mUsageTimeReport != null) { 1039 b.putParcelable(KEY_USAGE_TIME_REPORT, mUsageTimeReport); 1040 } 1041 switch (mAnimationType) { 1042 case ANIM_CUSTOM: 1043 b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId); 1044 b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId); 1045 b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener 1046 != null ? mAnimationStartedListener.asBinder() : null); 1047 break; 1048 case ANIM_CUSTOM_IN_PLACE: 1049 b.putInt(KEY_ANIM_IN_PLACE_RES_ID, mCustomInPlaceResId); 1050 break; 1051 case ANIM_SCALE_UP: 1052 case ANIM_CLIP_REVEAL: 1053 b.putInt(KEY_ANIM_START_X, mStartX); 1054 b.putInt(KEY_ANIM_START_Y, mStartY); 1055 b.putInt(KEY_ANIM_WIDTH, mWidth); 1056 b.putInt(KEY_ANIM_HEIGHT, mHeight); 1057 break; 1058 case ANIM_THUMBNAIL_SCALE_UP: 1059 case ANIM_THUMBNAIL_SCALE_DOWN: 1060 case ANIM_THUMBNAIL_ASPECT_SCALE_UP: 1061 case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN: 1062 b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail); 1063 b.putInt(KEY_ANIM_START_X, mStartX); 1064 b.putInt(KEY_ANIM_START_Y, mStartY); 1065 b.putInt(KEY_ANIM_WIDTH, mWidth); 1066 b.putInt(KEY_ANIM_HEIGHT, mHeight); 1067 b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener 1068 != null ? mAnimationStartedListener.asBinder() : null); 1069 break; 1070 case ANIM_SCENE_TRANSITION: 1071 if (mTransitionReceiver != null) { 1072 b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mTransitionReceiver); 1073 } 1074 b.putBoolean(KEY_TRANSITION_IS_RETURNING, mIsReturning); 1075 b.putStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS, mSharedElementNames); 1076 b.putParcelable(KEY_RESULT_DATA, mResultData); 1077 b.putInt(KEY_RESULT_CODE, mResultCode); 1078 b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex); 1079 break; 1080 } 1081 b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId); 1082 b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode); 1083 if (mAnimSpecs != null) { 1084 b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs); 1085 } 1086 if (mAnimationFinishedListener != null) { 1087 b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder()); 1088 } 1089 1090 return b; 1091 } 1092 1093 /** 1094 * Ask the the system track that time the user spends in the app being launched, and 1095 * report it back once done. The report will be sent to the given receiver, with 1096 * the extras {@link #EXTRA_USAGE_TIME_REPORT} and {@link #EXTRA_USAGE_TIME_REPORT_PACKAGES} 1097 * filled in. 1098 * 1099 * <p>The time interval tracked is from launching this activity until the user leaves 1100 * that activity's flow. They are considered to stay in the flow as long as 1101 * new activities are being launched or returned to from the original flow, 1102 * even if this crosses package or task boundaries. For example, if the originator 1103 * starts an activity to view an image, and while there the user selects to share, 1104 * which launches their email app in a new task, and they complete the share, the 1105 * time during that entire operation will be included until they finally hit back from 1106 * the original image viewer activity.</p> 1107 * 1108 * <p>The user is considered to complete a flow once they switch to another 1109 * activity that is not part of the tracked flow. This may happen, for example, by 1110 * using the notification shade, launcher, or recents to launch or switch to another 1111 * app. Simply going in to these navigation elements does not break the flow (although 1112 * the launcher and recents stops time tracking of the session); it is the act of 1113 * going somewhere else that completes the tracking.</p> 1114 * 1115 * @param receiver A broadcast receiver that willl receive the report. 1116 */ 1117 public void requestUsageTimeReport(PendingIntent receiver) { 1118 mUsageTimeReport = receiver; 1119 } 1120 1121 /** 1122 * Return the filtered options only meant to be seen by the target activity itself 1123 * @hide 1124 */ 1125 public ActivityOptions forTargetActivity() { 1126 if (mAnimationType == ANIM_SCENE_TRANSITION) { 1127 final ActivityOptions result = new ActivityOptions(); 1128 result.update(this); 1129 return result; 1130 } 1131 1132 return null; 1133 } 1134 1135 /** @hide */ 1136 @Override 1137 public String toString() { 1138 return "ActivityOptions(" + hashCode() + "), mPackageName=" + mPackageName 1139 + ", mAnimationType=" + mAnimationType + ", mStartX=" + mStartX + ", mStartY=" 1140 + mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight; 1141 } 1142} 1143