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