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