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