ActivityOptions.java revision e180337ee99b9155fe441ea55451f4d2167b5d9a
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.graphics.Bitmap; 21import android.os.Bundle; 22import android.os.Handler; 23import android.os.IRemoteCallback; 24import android.os.RemoteException; 25import android.transition.Transition; 26import android.util.Log; 27import android.util.Pair; 28import android.view.View; 29 30import java.util.ArrayList; 31import java.util.Map; 32 33/** 34 * Helper class for building an options Bundle that can be used with 35 * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle) 36 * Context.startActivity(Intent, Bundle)} and related methods. 37 */ 38public class ActivityOptions { 39 private static final String TAG = "ActivityOptions"; 40 41 /** 42 * The package name that created the options. 43 * @hide 44 */ 45 public static final String KEY_PACKAGE_NAME = "android:packageName"; 46 47 /** 48 * Type of animation that arguments specify. 49 * @hide 50 */ 51 public static final String KEY_ANIM_TYPE = "android:animType"; 52 53 /** 54 * Custom enter animation resource ID. 55 * @hide 56 */ 57 public static final String KEY_ANIM_ENTER_RES_ID = "android:animEnterRes"; 58 59 /** 60 * Custom exit animation resource ID. 61 * @hide 62 */ 63 public static final String KEY_ANIM_EXIT_RES_ID = "android:animExitRes"; 64 65 /** 66 * Bitmap for thumbnail animation. 67 * @hide 68 */ 69 public static final String KEY_ANIM_THUMBNAIL = "android:animThumbnail"; 70 71 /** 72 * Start X position of thumbnail animation. 73 * @hide 74 */ 75 public static final String KEY_ANIM_START_X = "android:animStartX"; 76 77 /** 78 * Start Y position of thumbnail animation. 79 * @hide 80 */ 81 public static final String KEY_ANIM_START_Y = "android:animStartY"; 82 83 /** 84 * Initial width of the animation. 85 * @hide 86 */ 87 public static final String KEY_ANIM_START_WIDTH = "android:animStartWidth"; 88 89 /** 90 * Initial height of the animation. 91 * @hide 92 */ 93 public static final String KEY_ANIM_START_HEIGHT = "android:animStartHeight"; 94 95 /** 96 * Callback for when animation is started. 97 * @hide 98 */ 99 public static final String KEY_ANIM_START_LISTENER = "android:animStartListener"; 100 101 /** 102 * For Activity transitions, the calling Activity's TransitionListener used to 103 * notify the called Activity when the shared element and the exit transitions 104 * complete. 105 */ 106 private static final String KEY_TRANSITION_COMPLETE_LISTENER 107 = "android:transitionCompleteListener"; 108 109 /** 110 * For Activity transitions, the called Activity's listener to receive calls 111 * when transitions complete. 112 */ 113 private static final String KEY_TRANSITION_TARGET_LISTENER = "android:transitionTargetListener"; 114 115 /** 116 * The names of shared elements that are transitioned to the started Activity. 117 * This is also the name of shared elements that the started Activity accepted. 118 */ 119 private static final String KEY_SHARED_ELEMENT_NAMES = "android:shared_element_names"; 120 121 /** 122 * The shared elements names of the views in the calling Activity. 123 */ 124 private static final String KEY_LOCAL_ELEMENT_NAMES = "android:local_element_names"; 125 126 /** @hide */ 127 public static final int ANIM_NONE = 0; 128 /** @hide */ 129 public static final int ANIM_CUSTOM = 1; 130 /** @hide */ 131 public static final int ANIM_SCALE_UP = 2; 132 /** @hide */ 133 public static final int ANIM_THUMBNAIL_SCALE_UP = 3; 134 /** @hide */ 135 public static final int ANIM_THUMBNAIL_SCALE_DOWN = 4; 136 /** @hide */ 137 public static final int ANIM_SCENE_TRANSITION = 5; 138 139 private String mPackageName; 140 private int mAnimationType = ANIM_NONE; 141 private int mCustomEnterResId; 142 private int mCustomExitResId; 143 private Bitmap mThumbnail; 144 private int mStartX; 145 private int mStartY; 146 private int mStartWidth; 147 private int mStartHeight; 148 private IRemoteCallback mAnimationStartedListener; 149 private IRemoteCallback mTransitionCompleteListener; 150 private ArrayList<String> mSharedElementNames; 151 private ArrayList<String> mLocalElementNames; 152 153 /** 154 * Create an ActivityOptions specifying a custom animation to run when 155 * the activity is displayed. 156 * 157 * @param context Who is defining this. This is the application that the 158 * animation resources will be loaded from. 159 * @param enterResId A resource ID of the animation resource to use for 160 * the incoming activity. Use 0 for no animation. 161 * @param exitResId A resource ID of the animation resource to use for 162 * the outgoing activity. Use 0 for no animation. 163 * @return Returns a new ActivityOptions object that you can use to 164 * supply these options as the options Bundle when starting an activity. 165 */ 166 public static ActivityOptions makeCustomAnimation(Context context, 167 int enterResId, int exitResId) { 168 return makeCustomAnimation(context, enterResId, exitResId, null, null); 169 } 170 171 /** 172 * Create an ActivityOptions specifying a custom animation to run when 173 * the activity is displayed. 174 * 175 * @param context Who is defining this. This is the application that the 176 * animation resources will be loaded from. 177 * @param enterResId A resource ID of the animation resource to use for 178 * the incoming activity. Use 0 for no animation. 179 * @param exitResId A resource ID of the animation resource to use for 180 * the outgoing activity. Use 0 for no animation. 181 * @param handler If <var>listener</var> is non-null this must be a valid 182 * Handler on which to dispatch the callback; otherwise it should be null. 183 * @param listener Optional OnAnimationStartedListener to find out when the 184 * requested animation has started running. If for some reason the animation 185 * is not executed, the callback will happen immediately. 186 * @return Returns a new ActivityOptions object that you can use to 187 * supply these options as the options Bundle when starting an activity. 188 * @hide 189 */ 190 public static ActivityOptions makeCustomAnimation(Context context, 191 int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener) { 192 ActivityOptions opts = new ActivityOptions(); 193 opts.mPackageName = context.getPackageName(); 194 opts.mAnimationType = ANIM_CUSTOM; 195 opts.mCustomEnterResId = enterResId; 196 opts.mCustomExitResId = exitResId; 197 opts.setOnAnimationStartedListener(handler, listener); 198 return opts; 199 } 200 201 private void setOnAnimationStartedListener(Handler handler, 202 OnAnimationStartedListener listener) { 203 if (listener != null) { 204 final Handler h = handler; 205 final OnAnimationStartedListener finalListener = listener; 206 mAnimationStartedListener = new IRemoteCallback.Stub() { 207 @Override public void sendResult(Bundle data) throws RemoteException { 208 h.post(new Runnable() { 209 @Override public void run() { 210 finalListener.onAnimationStarted(); 211 } 212 }); 213 } 214 }; 215 } 216 } 217 218 /** 219 * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation} 220 * to find out when the given animation has started running. 221 * @hide 222 */ 223 public interface OnAnimationStartedListener { 224 void onAnimationStarted(); 225 } 226 227 /** @hide */ 228 public interface ActivityTransitionTarget { 229 void sharedElementTransitionComplete(Bundle transitionArgs); 230 void exitTransitionComplete(); 231 } 232 233 /** 234 * Create an ActivityOptions specifying an animation where the new 235 * activity is scaled from a small originating area of the screen to 236 * its final full representation. 237 * 238 * <p>If the Intent this is being used with has not set its 239 * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds}, 240 * those bounds will be filled in for you based on the initial 241 * bounds passed in here. 242 * 243 * @param source The View that the new activity is animating from. This 244 * defines the coordinate space for <var>startX</var> and <var>startY</var>. 245 * @param startX The x starting location of the new activity, relative to <var>source</var>. 246 * @param startY The y starting location of the activity, relative to <var>source</var>. 247 * @param startWidth The initial width of the new activity. 248 * @param startHeight The initial height of the new activity. 249 * @return Returns a new ActivityOptions object that you can use to 250 * supply these options as the options Bundle when starting an activity. 251 */ 252 public static ActivityOptions makeScaleUpAnimation(View source, 253 int startX, int startY, int startWidth, int startHeight) { 254 ActivityOptions opts = new ActivityOptions(); 255 opts.mPackageName = source.getContext().getPackageName(); 256 opts.mAnimationType = ANIM_SCALE_UP; 257 int[] pts = new int[2]; 258 source.getLocationOnScreen(pts); 259 opts.mStartX = pts[0] + startX; 260 opts.mStartY = pts[1] + startY; 261 opts.mStartWidth = startWidth; 262 opts.mStartHeight = startHeight; 263 return opts; 264 } 265 266 /** 267 * Create an ActivityOptions specifying an animation where a thumbnail 268 * is scaled from a given position to the new activity window that is 269 * being started. 270 * 271 * <p>If the Intent this is being used with has not set its 272 * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds}, 273 * those bounds will be filled in for you based on the initial 274 * thumbnail location and size provided here. 275 * 276 * @param source The View that this thumbnail is animating from. This 277 * defines the coordinate space for <var>startX</var> and <var>startY</var>. 278 * @param thumbnail The bitmap that will be shown as the initial thumbnail 279 * of the animation. 280 * @param startX The x starting location of the bitmap, relative to <var>source</var>. 281 * @param startY The y starting location of the bitmap, relative to <var>source</var>. 282 * @return Returns a new ActivityOptions object that you can use to 283 * supply these options as the options Bundle when starting an activity. 284 */ 285 public static ActivityOptions makeThumbnailScaleUpAnimation(View source, 286 Bitmap thumbnail, int startX, int startY) { 287 return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, null); 288 } 289 290 /** 291 * Create an ActivityOptions specifying an animation where a thumbnail 292 * is scaled from a given position to the new activity window that is 293 * being started. 294 * 295 * @param source The View that this thumbnail is animating from. This 296 * defines the coordinate space for <var>startX</var> and <var>startY</var>. 297 * @param thumbnail The bitmap that will be shown as the initial thumbnail 298 * of the animation. 299 * @param startX The x starting location of the bitmap, relative to <var>source</var>. 300 * @param startY The y starting location of the bitmap, relative to <var>source</var>. 301 * @param listener Optional OnAnimationStartedListener to find out when the 302 * requested animation has started running. If for some reason the animation 303 * is not executed, the callback will happen immediately. 304 * @return Returns a new ActivityOptions object that you can use to 305 * supply these options as the options Bundle when starting an activity. 306 * @hide 307 */ 308 public static ActivityOptions makeThumbnailScaleUpAnimation(View source, 309 Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) { 310 return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true); 311 } 312 313 /** 314 * Create an ActivityOptions specifying an animation where an activity window 315 * is scaled from a given position to a thumbnail at a specified location. 316 * 317 * @param source The View that this thumbnail is animating to. This 318 * defines the coordinate space for <var>startX</var> and <var>startY</var>. 319 * @param thumbnail The bitmap that will be shown as the final thumbnail 320 * of the animation. 321 * @param startX The x end location of the bitmap, relative to <var>source</var>. 322 * @param startY The y end location of the bitmap, relative to <var>source</var>. 323 * @param listener Optional OnAnimationStartedListener to find out when the 324 * requested animation has started running. If for some reason the animation 325 * is not executed, the callback will happen immediately. 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 * @hide 329 */ 330 public static ActivityOptions makeThumbnailScaleDownAnimation(View source, 331 Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) { 332 return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, false); 333 } 334 335 private static ActivityOptions makeThumbnailAnimation(View source, 336 Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener, 337 boolean scaleUp) { 338 ActivityOptions opts = new ActivityOptions(); 339 opts.mPackageName = source.getContext().getPackageName(); 340 opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN; 341 opts.mThumbnail = thumbnail; 342 int[] pts = new int[2]; 343 source.getLocationOnScreen(pts); 344 opts.mStartX = pts[0] + startX; 345 opts.mStartY = pts[1] + startY; 346 opts.setOnAnimationStartedListener(source.getHandler(), listener); 347 return opts; 348 } 349 350 /** 351 * Create an ActivityOptions to transition between Activities using cross-Activity scene 352 * animations. This method carries the position of one shared element to the started Activity. 353 * 354 * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be 355 * enabled on the calling Activity to cause an exit transition. The same must be in 356 * the called Activity to get an entering transition.</p> 357 * @param sharedElement The View to transition to the started Activity. sharedElement must 358 * have a non-null sharedElementName. 359 * @param sharedElementName The shared element name as used in the target Activity. This may 360 * be null if it has the same name as sharedElement. 361 * @return Returns a new ActivityOptions object that you can use to 362 * supply these options as the options Bundle when starting an activity. 363 */ 364 public static ActivityOptions makeSceneTransitionAnimation(View sharedElement, 365 String sharedElementName) { 366 return makeSceneTransitionAnimation( 367 new Pair<View, String>(sharedElement, sharedElementName)); 368 } 369 370 /** 371 * Create an ActivityOptions to transition between Activities using cross-Activity scene 372 * animations. This method carries the position of multiple shared elements to the started 373 * Activity. 374 * 375 * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be 376 * enabled on the calling Activity to cause an exit transition. The same must be in 377 * the called Activity to get an entering transition.</p> 378 * @param sharedElements The View to transition to the started Activity along with the 379 * shared element name as used in the started Activity. The view 380 * must have a non-null sharedElementName. 381 * @return Returns a new ActivityOptions object that you can use to 382 * supply these options as the options Bundle when starting an activity. 383 */ 384 public static ActivityOptions makeSceneTransitionAnimation( 385 Pair<View, String>... sharedElements) { 386 ActivityOptions opts = new ActivityOptions(); 387 opts.mAnimationType = ANIM_SCENE_TRANSITION; 388 opts.mSharedElementNames = new ArrayList<String>(); 389 opts.mLocalElementNames = new ArrayList<String>(); 390 391 if (sharedElements != null) { 392 for (Pair<View, String> sharedElement : sharedElements) { 393 opts.addSharedElement(sharedElement.first, sharedElement.second); 394 } 395 } 396 return opts; 397 } 398 399 private ActivityOptions() { 400 } 401 402 /** @hide */ 403 public ActivityOptions(Bundle opts) { 404 mPackageName = opts.getString(KEY_PACKAGE_NAME); 405 mAnimationType = opts.getInt(KEY_ANIM_TYPE); 406 switch (mAnimationType) { 407 case ANIM_CUSTOM: 408 mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0); 409 mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0); 410 mAnimationStartedListener = IRemoteCallback.Stub.asInterface( 411 opts.getBinder(KEY_ANIM_START_LISTENER)); 412 break; 413 414 case ANIM_SCALE_UP: 415 mStartX = opts.getInt(KEY_ANIM_START_X, 0); 416 mStartY = opts.getInt(KEY_ANIM_START_Y, 0); 417 mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0); 418 mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0); 419 break; 420 421 case ANIM_THUMBNAIL_SCALE_UP: 422 case ANIM_THUMBNAIL_SCALE_DOWN: 423 mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL); 424 mStartX = opts.getInt(KEY_ANIM_START_X, 0); 425 mStartY = opts.getInt(KEY_ANIM_START_Y, 0); 426 mAnimationStartedListener = IRemoteCallback.Stub.asInterface( 427 opts.getBinder(KEY_ANIM_START_LISTENER)); 428 break; 429 430 case ANIM_SCENE_TRANSITION: 431 mTransitionCompleteListener = IRemoteCallback.Stub.asInterface( 432 opts.getBinder(KEY_TRANSITION_COMPLETE_LISTENER)); 433 mSharedElementNames = opts.getStringArrayList(KEY_SHARED_ELEMENT_NAMES); 434 mLocalElementNames = opts.getStringArrayList(KEY_LOCAL_ELEMENT_NAMES); 435 break; 436 } 437 } 438 439 /** @hide */ 440 public String getPackageName() { 441 return mPackageName; 442 } 443 444 /** @hide */ 445 public int getAnimationType() { 446 return mAnimationType; 447 } 448 449 /** @hide */ 450 public int getCustomEnterResId() { 451 return mCustomEnterResId; 452 } 453 454 /** @hide */ 455 public int getCustomExitResId() { 456 return mCustomExitResId; 457 } 458 459 /** @hide */ 460 public Bitmap getThumbnail() { 461 return mThumbnail; 462 } 463 464 /** @hide */ 465 public int getStartX() { 466 return mStartX; 467 } 468 469 /** @hide */ 470 public int getStartY() { 471 return mStartY; 472 } 473 474 /** @hide */ 475 public int getStartWidth() { 476 return mStartWidth; 477 } 478 479 /** @hide */ 480 public int getStartHeight() { 481 return mStartHeight; 482 } 483 484 /** @hide */ 485 public IRemoteCallback getOnAnimationStartListener() { 486 return mAnimationStartedListener; 487 } 488 489 /** @hide */ 490 public ArrayList<String> getSharedElementNames() { return mSharedElementNames; } 491 492 /** @hide */ 493 public ArrayList<String> getLocalElementNames() { return mLocalElementNames; } 494 495 /** @hide */ 496 public void dispatchSceneTransitionStarted(final ActivityTransitionTarget target, 497 ArrayList<String> sharedElementNames) { 498 boolean listenerSent = false; 499 if (mTransitionCompleteListener != null) { 500 IRemoteCallback callback = new IRemoteCallback.Stub() { 501 @Override 502 public void sendResult(Bundle data) throws RemoteException { 503 if (data == null) { 504 target.exitTransitionComplete(); 505 } else { 506 target.sharedElementTransitionComplete(data); 507 } 508 } 509 }; 510 Bundle bundle = new Bundle(); 511 bundle.putBinder(KEY_TRANSITION_TARGET_LISTENER, callback.asBinder()); 512 bundle.putStringArrayList(KEY_SHARED_ELEMENT_NAMES, sharedElementNames); 513 try { 514 mTransitionCompleteListener.sendResult(bundle); 515 listenerSent = true; 516 } catch (RemoteException e) { 517 Log.w(TAG, "Couldn't retrieve transition notifications", e); 518 } 519 } 520 if (!listenerSent) { 521 target.sharedElementTransitionComplete(null); 522 target.exitTransitionComplete(); 523 } 524 } 525 526 /** @hide */ 527 public void dispatchSharedElementsReady() { 528 if (mTransitionCompleteListener != null) { 529 try { 530 mTransitionCompleteListener.sendResult(null); 531 } catch (RemoteException e) { 532 Log.w(TAG, "Couldn't synchronize shared elements", e); 533 } 534 } 535 } 536 537 /** @hide */ 538 public void abort() { 539 if (mAnimationStartedListener != null) { 540 try { 541 mAnimationStartedListener.sendResult(null); 542 } catch (RemoteException e) { 543 } 544 } 545 } 546 547 /** @hide */ 548 public static void abort(Bundle options) { 549 if (options != null) { 550 (new ActivityOptions(options)).abort(); 551 } 552 } 553 554 /** 555 * Update the current values in this ActivityOptions from those supplied 556 * in <var>otherOptions</var>. Any values 557 * defined in <var>otherOptions</var> replace those in the base options. 558 */ 559 public void update(ActivityOptions otherOptions) { 560 if (otherOptions.mPackageName != null) { 561 mPackageName = otherOptions.mPackageName; 562 } 563 mSharedElementNames = null; 564 mLocalElementNames = null; 565 switch (otherOptions.mAnimationType) { 566 case ANIM_CUSTOM: 567 mAnimationType = otherOptions.mAnimationType; 568 mCustomEnterResId = otherOptions.mCustomEnterResId; 569 mCustomExitResId = otherOptions.mCustomExitResId; 570 mThumbnail = null; 571 if (mAnimationStartedListener != null) { 572 try { 573 mAnimationStartedListener.sendResult(null); 574 } catch (RemoteException e) { 575 } 576 } 577 mAnimationStartedListener = otherOptions.mAnimationStartedListener; 578 mTransitionCompleteListener = null; 579 break; 580 case ANIM_SCALE_UP: 581 mAnimationType = otherOptions.mAnimationType; 582 mStartX = otherOptions.mStartX; 583 mStartY = otherOptions.mStartY; 584 mStartWidth = otherOptions.mStartWidth; 585 mStartHeight = otherOptions.mStartHeight; 586 if (mAnimationStartedListener != null) { 587 try { 588 mAnimationStartedListener.sendResult(null); 589 } catch (RemoteException e) { 590 } 591 } 592 mAnimationStartedListener = null; 593 mTransitionCompleteListener = null; 594 break; 595 case ANIM_THUMBNAIL_SCALE_UP: 596 case ANIM_THUMBNAIL_SCALE_DOWN: 597 mAnimationType = otherOptions.mAnimationType; 598 mThumbnail = otherOptions.mThumbnail; 599 mStartX = otherOptions.mStartX; 600 mStartY = otherOptions.mStartY; 601 if (mAnimationStartedListener != null) { 602 try { 603 mAnimationStartedListener.sendResult(null); 604 } catch (RemoteException e) { 605 } 606 } 607 mAnimationStartedListener = otherOptions.mAnimationStartedListener; 608 mTransitionCompleteListener = null; 609 break; 610 case ANIM_SCENE_TRANSITION: 611 mAnimationType = otherOptions.mAnimationType; 612 mTransitionCompleteListener = otherOptions.mTransitionCompleteListener; 613 mThumbnail = null; 614 mAnimationStartedListener = null; 615 mSharedElementNames = otherOptions.mSharedElementNames; 616 mLocalElementNames = otherOptions.mLocalElementNames; 617 break; 618 } 619 } 620 621 /** 622 * Returns the created options as a Bundle, which can be passed to 623 * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle) 624 * Context.startActivity(Intent, Bundle)} and related methods. 625 * Note that the returned Bundle is still owned by the ActivityOptions 626 * object; you must not modify it, but can supply it to the startActivity 627 * methods that take an options Bundle. 628 */ 629 public Bundle toBundle() { 630 Bundle b = new Bundle(); 631 if (mPackageName != null) { 632 b.putString(KEY_PACKAGE_NAME, mPackageName); 633 } 634 switch (mAnimationType) { 635 case ANIM_CUSTOM: 636 b.putInt(KEY_ANIM_TYPE, mAnimationType); 637 b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId); 638 b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId); 639 b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener 640 != null ? mAnimationStartedListener.asBinder() : null); 641 break; 642 case ANIM_SCALE_UP: 643 b.putInt(KEY_ANIM_TYPE, mAnimationType); 644 b.putInt(KEY_ANIM_START_X, mStartX); 645 b.putInt(KEY_ANIM_START_Y, mStartY); 646 b.putInt(KEY_ANIM_START_WIDTH, mStartWidth); 647 b.putInt(KEY_ANIM_START_HEIGHT, mStartHeight); 648 break; 649 case ANIM_THUMBNAIL_SCALE_UP: 650 case ANIM_THUMBNAIL_SCALE_DOWN: 651 b.putInt(KEY_ANIM_TYPE, mAnimationType); 652 b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail); 653 b.putInt(KEY_ANIM_START_X, mStartX); 654 b.putInt(KEY_ANIM_START_Y, mStartY); 655 b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener 656 != null ? mAnimationStartedListener.asBinder() : null); 657 break; 658 case ANIM_SCENE_TRANSITION: 659 b.putInt(KEY_ANIM_TYPE, mAnimationType); 660 if (mTransitionCompleteListener != null) { 661 b.putBinder(KEY_TRANSITION_COMPLETE_LISTENER, 662 mTransitionCompleteListener.asBinder()); 663 } 664 b.putStringArrayList(KEY_SHARED_ELEMENT_NAMES, mSharedElementNames); 665 b.putStringArrayList(KEY_LOCAL_ELEMENT_NAMES, mLocalElementNames); 666 break; 667 } 668 return b; 669 } 670 671 /** 672 * Return the filtered options only meant to be seen by the target activity itself 673 * @hide 674 */ 675 public ActivityOptions forTargetActivity() { 676 if (mAnimationType == ANIM_SCENE_TRANSITION) { 677 final ActivityOptions result = new ActivityOptions(); 678 result.update(this); 679 return result; 680 } 681 682 return null; 683 } 684 685 /** @hide */ 686 public void addSharedElements(Map<String, View> sharedElements) { 687 for (Map.Entry<String, View> entry : sharedElements.entrySet()) { 688 addSharedElement(entry.getValue(), entry.getKey()); 689 } 690 } 691 692 /** @hide */ 693 public void updateSceneTransitionAnimation(Transition exitTransition, 694 Transition sharedElementTransition, SharedElementSource sharedElementSource) { 695 mTransitionCompleteListener = new ExitTransitionListener(exitTransition, 696 sharedElementTransition, sharedElementSource); 697 } 698 699 private void addSharedElement(View view, String name) { 700 String sharedElementName = view.getSharedElementName(); 701 if (name == null) { 702 name = sharedElementName; 703 } 704 mSharedElementNames.add(name); 705 mLocalElementNames.add(sharedElementName); 706 } 707 708 /** @hide */ 709 public interface SharedElementSource { 710 Bundle getSharedElementExitState(); 711 void acceptedSharedElements(ArrayList<String> sharedElementNames); 712 void hideSharedElements(); 713 } 714 715 private static class ExitTransitionListener extends IRemoteCallback.Stub 716 implements Transition.TransitionListener { 717 private boolean mSharedElementNotified; 718 private Transition mExitTransition; 719 private Transition mSharedElementTransition; 720 private IRemoteCallback mTransitionCompleteCallback; 721 private boolean mExitComplete; 722 private boolean mSharedElementComplete; 723 private SharedElementSource mSharedElementSource; 724 725 public ExitTransitionListener(Transition exitTransition, Transition sharedElementTransition, 726 SharedElementSource sharedElementSource) { 727 mSharedElementSource = sharedElementSource; 728 mExitTransition = exitTransition; 729 mExitTransition.addListener(this); 730 mSharedElementTransition = sharedElementTransition; 731 mSharedElementTransition.addListener(this); 732 } 733 734 @Override 735 public void sendResult(Bundle data) throws RemoteException { 736 if (data != null) { 737 mTransitionCompleteCallback = IRemoteCallback.Stub.asInterface( 738 data.getBinder(KEY_TRANSITION_TARGET_LISTENER)); 739 ArrayList<String> sharedElementNames 740 = data.getStringArrayList(KEY_SHARED_ELEMENT_NAMES); 741 mSharedElementSource.acceptedSharedElements(sharedElementNames); 742 notifySharedElement(); 743 notifyExit(); 744 } else { 745 mSharedElementSource.hideSharedElements(); 746 } 747 } 748 749 @Override 750 public void onTransitionStart(Transition transition) { 751 } 752 753 @Override 754 public void onTransitionEnd(Transition transition) { 755 if (transition == mExitTransition) { 756 mExitComplete = true; 757 notifyExit(); 758 mExitTransition.removeListener(this); 759 } else { 760 mSharedElementComplete = true; 761 notifySharedElement(); 762 mSharedElementTransition.removeListener(this); 763 } 764 } 765 766 @Override 767 public void onTransitionCancel(Transition transition) { 768 onTransitionEnd(transition); 769 } 770 771 @Override 772 public void onTransitionPause(Transition transition) { 773 } 774 775 @Override 776 public void onTransitionResume(Transition transition) { 777 } 778 779 private void notifySharedElement() { 780 if (!mSharedElementNotified && mSharedElementComplete 781 && mTransitionCompleteCallback != null) { 782 mSharedElementNotified = true; 783 try { 784 Bundle sharedElementState = mSharedElementSource.getSharedElementExitState(); 785 mTransitionCompleteCallback.sendResult(sharedElementState); 786 } catch (RemoteException e) { 787 Log.w(TAG, "Couldn't notify that the transition ended", e); 788 } 789 } 790 } 791 792 private void notifyExit() { 793 if (mExitComplete && mTransitionCompleteCallback != null) { 794 try { 795 mTransitionCompleteCallback.sendResult(null); 796 } catch (RemoteException e) { 797 Log.w(TAG, "Couldn't notify that the transition ended", e); 798 } 799 } 800 } 801 } 802} 803