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