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 17 package android.app; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.graphics.Bitmap; 22 import android.os.Bundle; 23 import android.os.Handler; 24 import android.os.IRemoteCallback; 25 import android.os.RemoteException; 26 import android.os.ResultReceiver; 27 import android.util.Pair; 28 import android.util.Slog; 29 import android.view.View; 30 import android.view.Window; 31 32 import 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 */ 39 public 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 */ makeCustomAnimation(Context context, int enterResId, int exitResId)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 */ makeCustomAnimation(Context context, int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener)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 */ makeCustomInPlaceAnimation(Context context, int animId)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 setOnAnimationStartedListener(Handler handler, OnAnimationStartedListener listener)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 { onAnimationStarted()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 */ makeScaleUpAnimation(View source, int startX, int startY, int width, int height)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 */ makeClipRevealAnimation(View source, int startX, int startY, int width, int height)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 */ makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY)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 */ makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener)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 */ makeThumbnailScaleDownAnimation(View source, Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener)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 makeThumbnailAnimation(View source, Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener, boolean scaleUp)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 */ makeThumbnailAspectScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight, Handler handler, OnAnimationStartedListener listener)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 */ makeThumbnailAspectScaleDownAnimation(View source, Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight, Handler handler, OnAnimationStartedListener listener)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 makeAspectScaledThumbnailAnimation(View source, Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight, Handler handler, OnAnimationStartedListener listener, boolean scaleUp)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 */ makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName)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 */ makeSceneTransitionAnimation(Activity activity, Pair<View, String>... sharedElements)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 */ makeSceneTransitionAnimation(Activity activity, ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames, int resultCode, Intent resultData)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 */ makeTaskLaunchBehind()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 */ makeBasic()613 public static ActivityOptions makeBasic() { 614 final ActivityOptions opts = new ActivityOptions(); 615 return opts; 616 } 617 618 /** @hide */ getLaunchTaskBehind()619 public boolean getLaunchTaskBehind() { 620 return mAnimationType == ANIM_LAUNCH_TASK_BEHIND; 621 } 622 ActivityOptions()623 private ActivityOptions() { 624 } 625 626 /** @hide */ ActivityOptions(Bundle opts)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 */ getPackageName()680 public String getPackageName() { 681 return mPackageName; 682 } 683 684 /** @hide */ getAnimationType()685 public int getAnimationType() { 686 return mAnimationType; 687 } 688 689 /** @hide */ getCustomEnterResId()690 public int getCustomEnterResId() { 691 return mCustomEnterResId; 692 } 693 694 /** @hide */ getCustomExitResId()695 public int getCustomExitResId() { 696 return mCustomExitResId; 697 } 698 699 /** @hide */ getCustomInPlaceResId()700 public int getCustomInPlaceResId() { 701 return mCustomInPlaceResId; 702 } 703 704 /** @hide */ getThumbnail()705 public Bitmap getThumbnail() { 706 return mThumbnail; 707 } 708 709 /** @hide */ getStartX()710 public int getStartX() { 711 return mStartX; 712 } 713 714 /** @hide */ getStartY()715 public int getStartY() { 716 return mStartY; 717 } 718 719 /** @hide */ getWidth()720 public int getWidth() { 721 return mWidth; 722 } 723 724 /** @hide */ getHeight()725 public int getHeight() { 726 return mHeight; 727 } 728 729 /** @hide */ getOnAnimationStartListener()730 public IRemoteCallback getOnAnimationStartListener() { 731 return mAnimationStartedListener; 732 } 733 734 /** @hide */ getExitCoordinatorKey()735 public int getExitCoordinatorKey() { return mExitCoordinatorIndex; } 736 737 /** @hide */ abort()738 public void abort() { 739 if (mAnimationStartedListener != null) { 740 try { 741 mAnimationStartedListener.sendResult(null); 742 } catch (RemoteException e) { 743 } 744 } 745 } 746 747 /** @hide */ isReturning()748 public boolean isReturning() { 749 return mIsReturning; 750 } 751 752 /** @hide */ getSharedElementNames()753 public ArrayList<String> getSharedElementNames() { 754 return mSharedElementNames; 755 } 756 757 /** @hide */ getResultReceiver()758 public ResultReceiver getResultReceiver() { return mTransitionReceiver; } 759 760 /** @hide */ getResultCode()761 public int getResultCode() { return mResultCode; } 762 763 /** @hide */ getResultData()764 public Intent getResultData() { return mResultData; } 765 766 /** @hide */ getUsageTimeReport()767 public PendingIntent getUsageTimeReport() { 768 return mUsageTimeReport; 769 } 770 771 /** @hide */ abort(Bundle options)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 */ update(ActivityOptions otherOptions)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 */ toBundle()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 */ requestUsageTimeReport(PendingIntent receiver)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 */ forTargetActivity()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