ActivityOptions.java revision 854809c074aabebf5b6520c361d1d3c7c22066d2
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.content.Context; 23import android.content.Intent; 24import android.graphics.Bitmap; 25import android.graphics.Rect; 26import android.os.Bundle; 27import android.os.Handler; 28import android.os.IRemoteCallback; 29import android.os.Parcelable; 30import android.os.RemoteException; 31import android.os.ResultReceiver; 32import android.util.Pair; 33import android.util.Slog; 34import android.view.AppTransitionAnimationSpec; 35import android.view.View; 36import android.view.Window; 37 38import java.util.ArrayList; 39 40/** 41 * Helper class for building an options Bundle that can be used with 42 * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle) 43 * Context.startActivity(Intent, Bundle)} and related methods. 44 */ 45public class ActivityOptions { 46 private static final String TAG = "ActivityOptions"; 47 48 /** 49 * A long in the extras delivered by {@link #requestUsageTimeReport} that contains 50 * the total time (in ms) the user spent in the app flow. 51 */ 52 public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time"; 53 54 /** 55 * A Bundle in the extras delivered by {@link #requestUsageTimeReport} that contains 56 * detailed information about the time spent in each package associated with the app; 57 * each key is a package name, whose value is a long containing the time (in ms). 58 */ 59 public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages"; 60 61 /** 62 * The package name that created the options. 63 * @hide 64 */ 65 public static final String KEY_PACKAGE_NAME = "android:activity.packageName"; 66 67 /** 68 * The bounds (window size) that the activity should be launched in. Set to null explicitly for 69 * full screen. If the key is not found, previous bounds will be preserved. 70 * NOTE: This value is ignored on devices that don't have 71 * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or 72 * {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled. 73 * @hide 74 */ 75 public static final String KEY_LAUNCH_BOUNDS = "android:activity.launchBounds"; 76 77 /** 78 * Type of animation that arguments specify. 79 * @hide 80 */ 81 public static final String KEY_ANIM_TYPE = "android:activity.animType"; 82 83 /** 84 * Custom enter animation resource ID. 85 * @hide 86 */ 87 public static final String KEY_ANIM_ENTER_RES_ID = "android:activity.animEnterRes"; 88 89 /** 90 * Custom exit animation resource ID. 91 * @hide 92 */ 93 public static final String KEY_ANIM_EXIT_RES_ID = "android:activity.animExitRes"; 94 95 /** 96 * Custom in-place animation resource ID. 97 * @hide 98 */ 99 public static final String KEY_ANIM_IN_PLACE_RES_ID = "android:activity.animInPlaceRes"; 100 101 /** 102 * Bitmap for thumbnail animation. 103 * @hide 104 */ 105 public static final String KEY_ANIM_THUMBNAIL = "android:activity.animThumbnail"; 106 107 /** 108 * Start X position of thumbnail animation. 109 * @hide 110 */ 111 public static final String KEY_ANIM_START_X = "android:activity.animStartX"; 112 113 /** 114 * Start Y position of thumbnail animation. 115 * @hide 116 */ 117 public static final String KEY_ANIM_START_Y = "android:activity.animStartY"; 118 119 /** 120 * Initial width of the animation. 121 * @hide 122 */ 123 public static final String KEY_ANIM_WIDTH = "android:activity.animWidth"; 124 125 /** 126 * Initial height of the animation. 127 * @hide 128 */ 129 public static final String KEY_ANIM_HEIGHT = "android:activity.animHeight"; 130 131 /** 132 * Callback for when animation is started. 133 * @hide 134 */ 135 public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener"; 136 137 /** 138 * Callback for when the last frame of the animation is played. 139 * @hide 140 */ 141 private static final String KEY_ANIMATION_FINISHED_LISTENER = 142 "android:activity.animationFinishedListener"; 143 144 /** 145 * Descriptions of app transition animations to be played during the activity launch. 146 */ 147 private static final String KEY_ANIM_SPECS = "android:activity.animSpecs"; 148 149 /** 150 * The stack id the activity should be launched into. 151 * @hide 152 */ 153 private static final String KEY_LAUNCH_STACK_ID = "android.activity.launchStackId"; 154 155 /** 156 * Where the docked stack should be positioned. 157 * @hide 158 */ 159 private static final String KEY_DOCK_CREATE_MODE = "android:activity.dockCreateMode"; 160 161 /** 162 * For Activity transitions, the calling Activity's TransitionListener used to 163 * notify the called Activity when the shared element and the exit transitions 164 * complete. 165 */ 166 private static final String KEY_TRANSITION_COMPLETE_LISTENER 167 = "android:activity.transitionCompleteListener"; 168 169 private static final String KEY_TRANSITION_IS_RETURNING 170 = "android:activity.transitionIsReturning"; 171 private static final String KEY_TRANSITION_SHARED_ELEMENTS 172 = "android:activity.sharedElementNames"; 173 private static final String KEY_RESULT_DATA = "android:activity.resultData"; 174 private static final String KEY_RESULT_CODE = "android:activity.resultCode"; 175 private static final String KEY_EXIT_COORDINATOR_INDEX 176 = "android:activity.exitCoordinatorIndex"; 177 178 private static final String KEY_USAGE_TIME_REPORT = "android:activity.usageTimeReport"; 179 180 /** @hide */ 181 public static final int ANIM_NONE = 0; 182 /** @hide */ 183 public static final int ANIM_CUSTOM = 1; 184 /** @hide */ 185 public static final int ANIM_SCALE_UP = 2; 186 /** @hide */ 187 public static final int ANIM_THUMBNAIL_SCALE_UP = 3; 188 /** @hide */ 189 public static final int ANIM_THUMBNAIL_SCALE_DOWN = 4; 190 /** @hide */ 191 public static final int ANIM_SCENE_TRANSITION = 5; 192 /** @hide */ 193 public static final int ANIM_DEFAULT = 6; 194 /** @hide */ 195 public static final int ANIM_LAUNCH_TASK_BEHIND = 7; 196 /** @hide */ 197 public static final int ANIM_THUMBNAIL_ASPECT_SCALE_UP = 8; 198 /** @hide */ 199 public static final int ANIM_THUMBNAIL_ASPECT_SCALE_DOWN = 9; 200 /** @hide */ 201 public static final int ANIM_CUSTOM_IN_PLACE = 10; 202 /** @hide */ 203 public static final int ANIM_CLIP_REVEAL = 11; 204 205 private String mPackageName; 206 private boolean mHasLaunchBounds; 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 mHasLaunchBounds = opts.containsKey(KEY_LAUNCH_BOUNDS); 720 if (mHasLaunchBounds) { 721 mLaunchBounds = opts.getParcelable(KEY_LAUNCH_BOUNDS); 722 } 723 mAnimationType = opts.getInt(KEY_ANIM_TYPE); 724 switch (mAnimationType) { 725 case ANIM_CUSTOM: 726 mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0); 727 mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0); 728 mAnimationStartedListener = IRemoteCallback.Stub.asInterface( 729 opts.getBinder(KEY_ANIM_START_LISTENER)); 730 break; 731 732 case ANIM_CUSTOM_IN_PLACE: 733 mCustomInPlaceResId = opts.getInt(KEY_ANIM_IN_PLACE_RES_ID, 0); 734 break; 735 736 case ANIM_SCALE_UP: 737 case ANIM_CLIP_REVEAL: 738 mStartX = opts.getInt(KEY_ANIM_START_X, 0); 739 mStartY = opts.getInt(KEY_ANIM_START_Y, 0); 740 mWidth = opts.getInt(KEY_ANIM_WIDTH, 0); 741 mHeight = opts.getInt(KEY_ANIM_HEIGHT, 0); 742 break; 743 744 case ANIM_THUMBNAIL_SCALE_UP: 745 case ANIM_THUMBNAIL_SCALE_DOWN: 746 case ANIM_THUMBNAIL_ASPECT_SCALE_UP: 747 case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN: 748 mThumbnail = (Bitmap) opts.getParcelable(KEY_ANIM_THUMBNAIL); 749 mStartX = opts.getInt(KEY_ANIM_START_X, 0); 750 mStartY = opts.getInt(KEY_ANIM_START_Y, 0); 751 mWidth = opts.getInt(KEY_ANIM_WIDTH, 0); 752 mHeight = opts.getInt(KEY_ANIM_HEIGHT, 0); 753 mAnimationStartedListener = IRemoteCallback.Stub.asInterface( 754 opts.getBinder(KEY_ANIM_START_LISTENER)); 755 break; 756 757 case ANIM_SCENE_TRANSITION: 758 mTransitionReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER); 759 mIsReturning = opts.getBoolean(KEY_TRANSITION_IS_RETURNING, false); 760 mSharedElementNames = opts.getStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS); 761 mResultData = opts.getParcelable(KEY_RESULT_DATA); 762 mResultCode = opts.getInt(KEY_RESULT_CODE); 763 mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX); 764 break; 765 } 766 mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID); 767 mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT); 768 if (opts.containsKey(KEY_ANIM_SPECS)) { 769 Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS); 770 mAnimSpecs = new AppTransitionAnimationSpec[specs.length]; 771 for (int i = specs.length - 1; i >= 0; i--) { 772 mAnimSpecs[i] = (AppTransitionAnimationSpec) specs[i]; 773 } 774 } 775 if (opts.containsKey(KEY_ANIMATION_FINISHED_LISTENER)) { 776 mAnimationFinishedListener = IRemoteCallback.Stub.asInterface( 777 opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER)); 778 } 779 } 780 781 /** 782 * Sets the bounds (window size) that the activity should be launched in. Set to null explicitly 783 * for full screen. 784 * NOTE: This value is ignored on devices that don't have 785 * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} enabled. 786 */ 787 public ActivityOptions setLaunchBounds(Rect launchBounds) { 788 mHasLaunchBounds = true; 789 mLaunchBounds = launchBounds; 790 return this; 791 } 792 793 /** @hide */ 794 public String getPackageName() { 795 return mPackageName; 796 } 797 798 public boolean hasLaunchBounds() { 799 return mHasLaunchBounds; 800 } 801 802 public Rect getLaunchBounds(){ 803 return mLaunchBounds; 804 } 805 806 /** @hide */ 807 public int getAnimationType() { 808 return mAnimationType; 809 } 810 811 /** @hide */ 812 public int getCustomEnterResId() { 813 return mCustomEnterResId; 814 } 815 816 /** @hide */ 817 public int getCustomExitResId() { 818 return mCustomExitResId; 819 } 820 821 /** @hide */ 822 public int getCustomInPlaceResId() { 823 return mCustomInPlaceResId; 824 } 825 826 /** @hide */ 827 public Bitmap getThumbnail() { 828 return mThumbnail; 829 } 830 831 /** @hide */ 832 public int getStartX() { 833 return mStartX; 834 } 835 836 /** @hide */ 837 public int getStartY() { 838 return mStartY; 839 } 840 841 /** @hide */ 842 public int getWidth() { 843 return mWidth; 844 } 845 846 /** @hide */ 847 public int getHeight() { 848 return mHeight; 849 } 850 851 /** @hide */ 852 public IRemoteCallback getOnAnimationStartListener() { 853 return mAnimationStartedListener; 854 } 855 856 /** @hide */ 857 public IRemoteCallback getAnimationFinishedListener() { 858 return mAnimationFinishedListener; 859 } 860 861 /** @hide */ 862 public int getExitCoordinatorKey() { return mExitCoordinatorIndex; } 863 864 /** @hide */ 865 public void abort() { 866 if (mAnimationStartedListener != null) { 867 try { 868 mAnimationStartedListener.sendResult(null); 869 } catch (RemoteException e) { 870 } 871 } 872 } 873 874 /** @hide */ 875 public boolean isReturning() { 876 return mIsReturning; 877 } 878 879 /** @hide */ 880 public ArrayList<String> getSharedElementNames() { 881 return mSharedElementNames; 882 } 883 884 /** @hide */ 885 public ResultReceiver getResultReceiver() { return mTransitionReceiver; } 886 887 /** @hide */ 888 public int getResultCode() { return mResultCode; } 889 890 /** @hide */ 891 public Intent getResultData() { return mResultData; } 892 893 /** @hide */ 894 public PendingIntent getUsageTimeReport() { 895 return mUsageTimeReport; 896 } 897 898 /** @hide */ 899 public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; } 900 901 /** @hide */ 902 public static ActivityOptions fromBundle(Bundle bOptions) { 903 return bOptions != null ? new ActivityOptions(bOptions) : null; 904 } 905 906 /** @hide */ 907 public static void abort(ActivityOptions options) { 908 if (options != null) { 909 options.abort(); 910 } 911 } 912 913 /** @hide */ 914 public int getLaunchStackId() { 915 return mLaunchStackId; 916 } 917 918 /** @hide */ 919 public void setLaunchStackId(int launchStackId) { 920 mLaunchStackId = launchStackId; 921 } 922 923 /** @hide */ 924 public int getDockCreateMode() { 925 return mDockCreateMode; 926 } 927 928 /** @hide */ 929 public void setDockCreateMode(int dockCreateMode) { 930 mDockCreateMode = dockCreateMode; 931 } 932 933 /** 934 * Update the current values in this ActivityOptions from those supplied 935 * in <var>otherOptions</var>. Any values 936 * defined in <var>otherOptions</var> replace those in the base options. 937 */ 938 public void update(ActivityOptions otherOptions) { 939 if (otherOptions.mPackageName != null) { 940 mPackageName = otherOptions.mPackageName; 941 } 942 mUsageTimeReport = otherOptions.mUsageTimeReport; 943 mTransitionReceiver = null; 944 mSharedElementNames = null; 945 mIsReturning = false; 946 mResultData = null; 947 mResultCode = 0; 948 mExitCoordinatorIndex = 0; 949 mAnimationType = otherOptions.mAnimationType; 950 switch (otherOptions.mAnimationType) { 951 case ANIM_CUSTOM: 952 mCustomEnterResId = otherOptions.mCustomEnterResId; 953 mCustomExitResId = otherOptions.mCustomExitResId; 954 mThumbnail = null; 955 if (mAnimationStartedListener != null) { 956 try { 957 mAnimationStartedListener.sendResult(null); 958 } catch (RemoteException e) { 959 } 960 } 961 mAnimationStartedListener = otherOptions.mAnimationStartedListener; 962 break; 963 case ANIM_CUSTOM_IN_PLACE: 964 mCustomInPlaceResId = otherOptions.mCustomInPlaceResId; 965 break; 966 case ANIM_SCALE_UP: 967 mStartX = otherOptions.mStartX; 968 mStartY = otherOptions.mStartY; 969 mWidth = otherOptions.mWidth; 970 mHeight = otherOptions.mHeight; 971 if (mAnimationStartedListener != null) { 972 try { 973 mAnimationStartedListener.sendResult(null); 974 } catch (RemoteException e) { 975 } 976 } 977 mAnimationStartedListener = null; 978 break; 979 case ANIM_THUMBNAIL_SCALE_UP: 980 case ANIM_THUMBNAIL_SCALE_DOWN: 981 case ANIM_THUMBNAIL_ASPECT_SCALE_UP: 982 case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN: 983 mThumbnail = otherOptions.mThumbnail; 984 mStartX = otherOptions.mStartX; 985 mStartY = otherOptions.mStartY; 986 mWidth = otherOptions.mWidth; 987 mHeight = otherOptions.mHeight; 988 if (mAnimationStartedListener != null) { 989 try { 990 mAnimationStartedListener.sendResult(null); 991 } catch (RemoteException e) { 992 } 993 } 994 mAnimationStartedListener = otherOptions.mAnimationStartedListener; 995 break; 996 case ANIM_SCENE_TRANSITION: 997 mTransitionReceiver = otherOptions.mTransitionReceiver; 998 mSharedElementNames = otherOptions.mSharedElementNames; 999 mIsReturning = otherOptions.mIsReturning; 1000 mThumbnail = null; 1001 mAnimationStartedListener = null; 1002 mResultData = otherOptions.mResultData; 1003 mResultCode = otherOptions.mResultCode; 1004 mExitCoordinatorIndex = otherOptions.mExitCoordinatorIndex; 1005 break; 1006 } 1007 mAnimSpecs = otherOptions.mAnimSpecs; 1008 mAnimationFinishedListener = otherOptions.mAnimationFinishedListener; 1009 } 1010 1011 /** 1012 * Returns the created options as a Bundle, which can be passed to 1013 * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle) 1014 * Context.startActivity(Intent, Bundle)} and related methods. 1015 * Note that the returned Bundle is still owned by the ActivityOptions 1016 * object; you must not modify it, but can supply it to the startActivity 1017 * methods that take an options Bundle. 1018 */ 1019 public Bundle toBundle() { 1020 if (mAnimationType == ANIM_DEFAULT) { 1021 return null; 1022 } 1023 Bundle b = new Bundle(); 1024 if (mPackageName != null) { 1025 b.putString(KEY_PACKAGE_NAME, mPackageName); 1026 } 1027 if (mHasLaunchBounds) { 1028 b.putParcelable(KEY_LAUNCH_BOUNDS, mLaunchBounds); 1029 } 1030 b.putInt(KEY_ANIM_TYPE, mAnimationType); 1031 if (mUsageTimeReport != null) { 1032 b.putParcelable(KEY_USAGE_TIME_REPORT, mUsageTimeReport); 1033 } 1034 switch (mAnimationType) { 1035 case ANIM_CUSTOM: 1036 b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId); 1037 b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId); 1038 b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener 1039 != null ? mAnimationStartedListener.asBinder() : null); 1040 break; 1041 case ANIM_CUSTOM_IN_PLACE: 1042 b.putInt(KEY_ANIM_IN_PLACE_RES_ID, mCustomInPlaceResId); 1043 break; 1044 case ANIM_SCALE_UP: 1045 case ANIM_CLIP_REVEAL: 1046 b.putInt(KEY_ANIM_START_X, mStartX); 1047 b.putInt(KEY_ANIM_START_Y, mStartY); 1048 b.putInt(KEY_ANIM_WIDTH, mWidth); 1049 b.putInt(KEY_ANIM_HEIGHT, mHeight); 1050 break; 1051 case ANIM_THUMBNAIL_SCALE_UP: 1052 case ANIM_THUMBNAIL_SCALE_DOWN: 1053 case ANIM_THUMBNAIL_ASPECT_SCALE_UP: 1054 case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN: 1055 b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail); 1056 b.putInt(KEY_ANIM_START_X, mStartX); 1057 b.putInt(KEY_ANIM_START_Y, mStartY); 1058 b.putInt(KEY_ANIM_WIDTH, mWidth); 1059 b.putInt(KEY_ANIM_HEIGHT, mHeight); 1060 b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener 1061 != null ? mAnimationStartedListener.asBinder() : null); 1062 break; 1063 case ANIM_SCENE_TRANSITION: 1064 if (mTransitionReceiver != null) { 1065 b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mTransitionReceiver); 1066 } 1067 b.putBoolean(KEY_TRANSITION_IS_RETURNING, mIsReturning); 1068 b.putStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS, mSharedElementNames); 1069 b.putParcelable(KEY_RESULT_DATA, mResultData); 1070 b.putInt(KEY_RESULT_CODE, mResultCode); 1071 b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex); 1072 break; 1073 } 1074 b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId); 1075 b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode); 1076 if (mAnimSpecs != null) { 1077 b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs); 1078 } 1079 if (mAnimationFinishedListener != null) { 1080 b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder()); 1081 } 1082 1083 return b; 1084 } 1085 1086 /** 1087 * Ask the the system track that time the user spends in the app being launched, and 1088 * report it back once done. The report will be sent to the given receiver, with 1089 * the extras {@link #EXTRA_USAGE_TIME_REPORT} and {@link #EXTRA_USAGE_TIME_REPORT_PACKAGES} 1090 * filled in. 1091 * 1092 * <p>The time interval tracked is from launching this activity until the user leaves 1093 * that activity's flow. They are considered to stay in the flow as long as 1094 * new activities are being launched or returned to from the original flow, 1095 * even if this crosses package or task boundaries. For example, if the originator 1096 * starts an activity to view an image, and while there the user selects to share, 1097 * which launches their email app in a new task, and they complete the share, the 1098 * time during that entire operation will be included until they finally hit back from 1099 * the original image viewer activity.</p> 1100 * 1101 * <p>The user is considered to complete a flow once they switch to another 1102 * activity that is not part of the tracked flow. This may happen, for example, by 1103 * using the notification shade, launcher, or recents to launch or switch to another 1104 * app. Simply going in to these navigation elements does not break the flow (although 1105 * the launcher and recents stops time tracking of the session); it is the act of 1106 * going somewhere else that completes the tracking.</p> 1107 * 1108 * @param receiver A broadcast receiver that willl receive the report. 1109 */ 1110 public void requestUsageTimeReport(PendingIntent receiver) { 1111 mUsageTimeReport = receiver; 1112 } 1113 1114 /** 1115 * Return the filtered options only meant to be seen by the target activity itself 1116 * @hide 1117 */ 1118 public ActivityOptions forTargetActivity() { 1119 if (mAnimationType == ANIM_SCENE_TRANSITION) { 1120 final ActivityOptions result = new ActivityOptions(); 1121 result.update(this); 1122 return result; 1123 } 1124 1125 return null; 1126 } 1127 1128} 1129