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