ActivityOptions.java revision 18e905f42d017c4721d33bd25d7d39ef8d64b5d5
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.view.View; 26 27/** 28 * Helper class for building an options Bundle that can be used with 29 * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle) 30 * Context.startActivity(Intent, Bundle)} and related methods. 31 */ 32public class ActivityOptions { 33 /** 34 * The package name that created the options. 35 * @hide 36 */ 37 public static final String KEY_PACKAGE_NAME = "android:packageName"; 38 39 /** 40 * Type of animation that arguments specify. 41 * @hide 42 */ 43 public static final String KEY_ANIM_TYPE = "android:animType"; 44 45 /** 46 * Custom enter animation resource ID. 47 * @hide 48 */ 49 public static final String KEY_ANIM_ENTER_RES_ID = "android:animEnterRes"; 50 51 /** 52 * Custom exit animation resource ID. 53 * @hide 54 */ 55 public static final String KEY_ANIM_EXIT_RES_ID = "android:animExitRes"; 56 57 /** 58 * Bitmap for thumbnail animation. 59 * @hide 60 */ 61 public static final String KEY_ANIM_THUMBNAIL = "android:animThumbnail"; 62 63 /** 64 * Start X position of thumbnail animation. 65 * @hide 66 */ 67 public static final String KEY_ANIM_START_X = "android:animStartX"; 68 69 /** 70 * Start Y position of thumbnail animation. 71 * @hide 72 */ 73 public static final String KEY_ANIM_START_Y = "android:animStartY"; 74 75 /** 76 * Initial width of the animation. 77 * @hide 78 */ 79 public static final String KEY_ANIM_START_WIDTH = "android:animStartWidth"; 80 81 /** 82 * Initial height of the animation. 83 * @hide 84 */ 85 public static final String KEY_ANIM_START_HEIGHT = "android:animStartHeight"; 86 87 /** 88 * Callback for when animation is started. 89 * @hide 90 */ 91 public static final String KEY_ANIM_START_LISTENER = "android:animStartListener"; 92 93 /** 94 * A string array of names for the destination scene. This defines an API in the same 95 * way that intent action or extra names do and should follow a similar convention: 96 * "com.example.scene.FOO" 97 * 98 * @hide 99 */ 100 public static final String KEY_DEST_SCENE_NAMES = "android:destSceneNames"; 101 102 /** 103 * A string indicating the destination scene name that was chosen by the target. 104 * Used by {@link OnSceneTransitionStartedListener}. 105 * @hide 106 */ 107 public static final String KEY_DEST_SCENE_NAME_CHOSEN = "android:destSceneNameChosen"; 108 109 /** 110 * Callback for when scene transition is started. 111 * @hide 112 */ 113 public static final String KEY_SCENE_TRANSITION_START_LISTENER = 114 "android:sceneTransitionStartListener"; 115 116 /** 117 * Arguments for the scene transition about to begin. 118 * @hide 119 */ 120 public static final String KEY_SCENE_TRANSITION_ARGS = "android:sceneTransitionArgs"; 121 122 /** @hide */ 123 public static final int ANIM_NONE = 0; 124 /** @hide */ 125 public static final int ANIM_CUSTOM = 1; 126 /** @hide */ 127 public static final int ANIM_SCALE_UP = 2; 128 /** @hide */ 129 public static final int ANIM_THUMBNAIL_SCALE_UP = 3; 130 /** @hide */ 131 public static final int ANIM_THUMBNAIL_SCALE_DOWN = 4; 132 /** @hide */ 133 public static final int ANIM_SCENE_TRANSITION = 5; 134 135 private String mPackageName; 136 private int mAnimationType = ANIM_NONE; 137 private int mCustomEnterResId; 138 private int mCustomExitResId; 139 private Bitmap mThumbnail; 140 private int mStartX; 141 private int mStartY; 142 private int mStartWidth; 143 private int mStartHeight; 144 private String[] mDestSceneNames; 145 private Bundle mTransitionArgs; 146 private IRemoteCallback mAnimationStartedListener; 147 private IRemoteCallback mSceneTransitionStartedListener; 148 149 /** 150 * Create an ActivityOptions specifying a custom animation to run when 151 * the activity is displayed. 152 * 153 * @param context Who is defining this. This is the application that the 154 * animation resources will be loaded from. 155 * @param enterResId A resource ID of the animation resource to use for 156 * the incoming activity. Use 0 for no animation. 157 * @param exitResId A resource ID of the animation resource to use for 158 * the outgoing activity. Use 0 for no animation. 159 * @return Returns a new ActivityOptions object that you can use to 160 * supply these options as the options Bundle when starting an activity. 161 */ 162 public static ActivityOptions makeCustomAnimation(Context context, 163 int enterResId, int exitResId) { 164 return makeCustomAnimation(context, enterResId, exitResId, null, null); 165 } 166 167 /** 168 * Create an ActivityOptions specifying a custom animation to run when 169 * the activity is displayed. 170 * 171 * @param context Who is defining this. This is the application that the 172 * animation resources will be loaded from. 173 * @param enterResId A resource ID of the animation resource to use for 174 * the incoming activity. Use 0 for no animation. 175 * @param exitResId A resource ID of the animation resource to use for 176 * the outgoing activity. Use 0 for no animation. 177 * @param handler If <var>listener</var> is non-null this must be a valid 178 * Handler on which to dispatch the callback; otherwise it should be null. 179 * @param listener Optional OnAnimationStartedListener to find out when the 180 * requested animation has started running. If for some reason the animation 181 * is not executed, the callback will happen immediately. 182 * @return Returns a new ActivityOptions object that you can use to 183 * supply these options as the options Bundle when starting an activity. 184 * @hide 185 */ 186 public static ActivityOptions makeCustomAnimation(Context context, 187 int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener) { 188 ActivityOptions opts = new ActivityOptions(); 189 opts.mPackageName = context.getPackageName(); 190 opts.mAnimationType = ANIM_CUSTOM; 191 opts.mCustomEnterResId = enterResId; 192 opts.mCustomExitResId = exitResId; 193 opts.setOnAnimationStartedListener(handler, listener); 194 return opts; 195 } 196 197 private void setOnAnimationStartedListener(Handler handler, 198 OnAnimationStartedListener listener) { 199 if (listener != null) { 200 final Handler h = handler; 201 final OnAnimationStartedListener finalListener = listener; 202 mAnimationStartedListener = new IRemoteCallback.Stub() { 203 @Override public void sendResult(Bundle data) throws RemoteException { 204 h.post(new Runnable() { 205 @Override public void run() { 206 finalListener.onAnimationStarted(); 207 } 208 }); 209 } 210 }; 211 } 212 } 213 214 private void setOnSceneTransitionStartedListener(Handler handler, 215 OnSceneTransitionStartedListener listener) { 216 if (listener != null) { 217 final Handler h = handler; 218 final OnSceneTransitionStartedListener l = listener; 219 mSceneTransitionStartedListener = new IRemoteCallback.Stub() { 220 @Override public void sendResult(final Bundle data) throws RemoteException { 221 h.post(new Runnable() { 222 public void run() { 223 l.onSceneTransitionStarted(data != null ? 224 data.getString(KEY_DEST_SCENE_NAME_CHOSEN) : null); 225 } 226 }); 227 } 228 }; 229 } 230 } 231 232 /** 233 * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation} 234 * to find out when the given animation has started running. 235 * @hide 236 */ 237 public interface OnAnimationStartedListener { 238 void onAnimationStarted(); 239 } 240 241 /** 242 * Callback for use with {@link ActivityOptions#makeSceneTransitionAnimation} 243 * to find out when a transition is about to begin. 244 * @hide 245 */ 246 public interface OnSceneTransitionStartedListener { 247 void onSceneTransitionStarted(String destSceneName); 248 } 249 250 /** 251 * Create an ActivityOptions specifying an animation where the new 252 * activity is scaled from a small originating area of the screen to 253 * its final full representation. 254 * 255 * <p>If the Intent this is being used with has not set its 256 * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds}, 257 * those bounds will be filled in for you based on the initial 258 * bounds passed in here. 259 * 260 * @param source The View that the new activity is animating from. This 261 * defines the coordinate space for <var>startX</var> and <var>startY</var>. 262 * @param startX The x starting location of the new activity, relative to <var>source</var>. 263 * @param startY The y starting location of the activity, relative to <var>source</var>. 264 * @param startWidth The initial width of the new activity. 265 * @param startHeight The initial height of the new activity. 266 * @return Returns a new ActivityOptions object that you can use to 267 * supply these options as the options Bundle when starting an activity. 268 */ 269 public static ActivityOptions makeScaleUpAnimation(View source, 270 int startX, int startY, int startWidth, int startHeight) { 271 ActivityOptions opts = new ActivityOptions(); 272 opts.mPackageName = source.getContext().getPackageName(); 273 opts.mAnimationType = ANIM_SCALE_UP; 274 int[] pts = new int[2]; 275 source.getLocationOnScreen(pts); 276 opts.mStartX = pts[0] + startX; 277 opts.mStartY = pts[1] + startY; 278 opts.mStartWidth = startWidth; 279 opts.mStartHeight = startHeight; 280 return opts; 281 } 282 283 /** 284 * Create an ActivityOptions specifying an animation where a thumbnail 285 * is scaled from a given position to the new activity window that is 286 * being started. 287 * 288 * <p>If the Intent this is being used with has not set its 289 * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds}, 290 * those bounds will be filled in for you based on the initial 291 * thumbnail location and size provided here. 292 * 293 * @param source The View that this thumbnail is animating from. This 294 * defines the coordinate space for <var>startX</var> and <var>startY</var>. 295 * @param thumbnail The bitmap that will be shown as the initial thumbnail 296 * of the animation. 297 * @param startX The x starting location of the bitmap, relative to <var>source</var>. 298 * @param startY The y starting location of the bitmap, relative to <var>source</var>. 299 * @return Returns a new ActivityOptions object that you can use to 300 * supply these options as the options Bundle when starting an activity. 301 */ 302 public static ActivityOptions makeThumbnailScaleUpAnimation(View source, 303 Bitmap thumbnail, int startX, int startY) { 304 return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, null); 305 } 306 307 /** 308 * Create an ActivityOptions specifying an animation where a thumbnail 309 * is scaled from a given position to the new activity window that is 310 * being started. 311 * 312 * @param source The View that this thumbnail is animating from. This 313 * defines the coordinate space for <var>startX</var> and <var>startY</var>. 314 * @param thumbnail The bitmap that will be shown as the initial thumbnail 315 * of the animation. 316 * @param startX The x starting location of the bitmap, relative to <var>source</var>. 317 * @param startY The y starting location of the bitmap, relative to <var>source</var>. 318 * @param listener Optional OnAnimationStartedListener to find out when the 319 * requested animation has started running. If for some reason the animation 320 * is not executed, the callback will happen immediately. 321 * @return Returns a new ActivityOptions object that you can use to 322 * supply these options as the options Bundle when starting an activity. 323 * @hide 324 */ 325 public static ActivityOptions makeThumbnailScaleUpAnimation(View source, 326 Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) { 327 return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true); 328 } 329 330 /** 331 * Create an ActivityOptions specifying an animation where an activity window 332 * is scaled from a given position to a thumbnail at a specified location. 333 * 334 * @param source The View that this thumbnail is animating to. This 335 * defines the coordinate space for <var>startX</var> and <var>startY</var>. 336 * @param thumbnail The bitmap that will be shown as the final thumbnail 337 * of the animation. 338 * @param startX The x end location of the bitmap, relative to <var>source</var>. 339 * @param startY The y end location of the bitmap, relative to <var>source</var>. 340 * @param listener Optional OnAnimationStartedListener to find out when the 341 * requested animation has started running. If for some reason the animation 342 * is not executed, the callback will happen immediately. 343 * @return Returns a new ActivityOptions object that you can use to 344 * supply these options as the options Bundle when starting an activity. 345 * @hide 346 */ 347 public static ActivityOptions makeThumbnailScaleDownAnimation(View source, 348 Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) { 349 return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, false); 350 } 351 352 private static ActivityOptions makeThumbnailAnimation(View source, 353 Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener, 354 boolean scaleUp) { 355 ActivityOptions opts = new ActivityOptions(); 356 opts.mPackageName = source.getContext().getPackageName(); 357 opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN; 358 opts.mThumbnail = thumbnail; 359 int[] pts = new int[2]; 360 source.getLocationOnScreen(pts); 361 opts.mStartX = pts[0] + startX; 362 opts.mStartY = pts[1] + startY; 363 opts.setOnAnimationStartedListener(source.getHandler(), listener); 364 return opts; 365 } 366 367 /** 368 * Create an ActivityOptions specifying an animation where an activity window is asked 369 * to perform animations within the window content. 370 * 371 * @hide 372 */ 373 public static ActivityOptions makeSceneTransitionAnimation(String[] destSceneNames, 374 Bundle args, OnSceneTransitionStartedListener listener, Handler handler) { 375 ActivityOptions opts = new ActivityOptions(); 376 opts.mAnimationType = ANIM_SCENE_TRANSITION; 377 opts.mDestSceneNames = destSceneNames; 378 opts.mTransitionArgs = args; 379 opts.setOnSceneTransitionStartedListener(handler, listener); 380 return opts; 381 } 382 383 private ActivityOptions() { 384 } 385 386 /** @hide */ 387 public ActivityOptions(Bundle opts) { 388 mPackageName = opts.getString(KEY_PACKAGE_NAME); 389 mAnimationType = opts.getInt(KEY_ANIM_TYPE); 390 switch (mAnimationType) { 391 case ANIM_CUSTOM: 392 mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0); 393 mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0); 394 mAnimationStartedListener = IRemoteCallback.Stub.asInterface( 395 opts.getBinder(KEY_ANIM_START_LISTENER)); 396 break; 397 398 case ANIM_SCALE_UP: 399 mStartX = opts.getInt(KEY_ANIM_START_X, 0); 400 mStartY = opts.getInt(KEY_ANIM_START_Y, 0); 401 mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0); 402 mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0); 403 break; 404 405 case ANIM_THUMBNAIL_SCALE_UP: 406 case ANIM_THUMBNAIL_SCALE_DOWN: 407 mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL); 408 mStartX = opts.getInt(KEY_ANIM_START_X, 0); 409 mStartY = opts.getInt(KEY_ANIM_START_Y, 0); 410 mAnimationStartedListener = IRemoteCallback.Stub.asInterface( 411 opts.getBinder(KEY_ANIM_START_LISTENER)); 412 break; 413 414 case ANIM_SCENE_TRANSITION: 415 mDestSceneNames = opts.getStringArray(KEY_DEST_SCENE_NAMES); 416 mTransitionArgs = opts.getBundle(KEY_SCENE_TRANSITION_ARGS); 417 mSceneTransitionStartedListener = IRemoteCallback.Stub.asInterface( 418 opts.getBinder(KEY_SCENE_TRANSITION_START_LISTENER)); 419 break; 420 } 421 } 422 423 /** @hide */ 424 public String getPackageName() { 425 return mPackageName; 426 } 427 428 /** @hide */ 429 public int getAnimationType() { 430 return mAnimationType; 431 } 432 433 /** @hide */ 434 public int getCustomEnterResId() { 435 return mCustomEnterResId; 436 } 437 438 /** @hide */ 439 public int getCustomExitResId() { 440 return mCustomExitResId; 441 } 442 443 /** @hide */ 444 public Bitmap getThumbnail() { 445 return mThumbnail; 446 } 447 448 /** @hide */ 449 public int getStartX() { 450 return mStartX; 451 } 452 453 /** @hide */ 454 public int getStartY() { 455 return mStartY; 456 } 457 458 /** @hide */ 459 public int getStartWidth() { 460 return mStartWidth; 461 } 462 463 /** @hide */ 464 public int getStartHeight() { 465 return mStartHeight; 466 } 467 468 /** @hide */ 469 public String[] getDestSceneNames() { 470 return mDestSceneNames; 471 } 472 473 /** @hide */ 474 public Bundle getSceneTransitionArgs() { 475 return mTransitionArgs; 476 } 477 478 /** @hide */ 479 public IRemoteCallback getOnAnimationStartListener() { 480 return mAnimationStartedListener; 481 } 482 483 /** @hide */ 484 public IRemoteCallback getOnSceneTransitionStartedListener() { 485 return mSceneTransitionStartedListener; 486 } 487 488 /** @hide */ 489 public void abort() { 490 if (mAnimationStartedListener != null) { 491 try { 492 mAnimationStartedListener.sendResult(null); 493 } catch (RemoteException e) { 494 } 495 } 496 } 497 498 /** @hide */ 499 public static void abort(Bundle options) { 500 if (options != null) { 501 (new ActivityOptions(options)).abort(); 502 } 503 } 504 505 /** 506 * Update the current values in this ActivityOptions from those supplied 507 * in <var>otherOptions</var>. Any values 508 * defined in <var>otherOptions</var> replace those in the base options. 509 */ 510 public void update(ActivityOptions otherOptions) { 511 if (otherOptions.mPackageName != null) { 512 mPackageName = otherOptions.mPackageName; 513 } 514 switch (otherOptions.mAnimationType) { 515 case ANIM_CUSTOM: 516 mAnimationType = otherOptions.mAnimationType; 517 mCustomEnterResId = otherOptions.mCustomEnterResId; 518 mCustomExitResId = otherOptions.mCustomExitResId; 519 mThumbnail = null; 520 if (mAnimationStartedListener != null) { 521 try { 522 mAnimationStartedListener.sendResult(null); 523 } catch (RemoteException e) { 524 } 525 } 526 mAnimationStartedListener = otherOptions.mAnimationStartedListener; 527 mSceneTransitionStartedListener = null; 528 mTransitionArgs = null; 529 mDestSceneNames = null; 530 break; 531 case ANIM_SCALE_UP: 532 mAnimationType = otherOptions.mAnimationType; 533 mStartX = otherOptions.mStartX; 534 mStartY = otherOptions.mStartY; 535 mStartWidth = otherOptions.mStartWidth; 536 mStartHeight = otherOptions.mStartHeight; 537 if (mAnimationStartedListener != null) { 538 try { 539 mAnimationStartedListener.sendResult(null); 540 } catch (RemoteException e) { 541 } 542 } 543 mAnimationStartedListener = null; 544 mSceneTransitionStartedListener = null; 545 mTransitionArgs = null; 546 mDestSceneNames = null; 547 break; 548 case ANIM_THUMBNAIL_SCALE_UP: 549 case ANIM_THUMBNAIL_SCALE_DOWN: 550 mAnimationType = otherOptions.mAnimationType; 551 mThumbnail = otherOptions.mThumbnail; 552 mStartX = otherOptions.mStartX; 553 mStartY = otherOptions.mStartY; 554 if (mAnimationStartedListener != null) { 555 try { 556 mAnimationStartedListener.sendResult(null); 557 } catch (RemoteException e) { 558 } 559 } 560 mAnimationStartedListener = otherOptions.mAnimationStartedListener; 561 mSceneTransitionStartedListener = null; 562 mTransitionArgs = null; 563 mDestSceneNames = null; 564 break; 565 case ANIM_SCENE_TRANSITION: 566 mAnimationType = otherOptions.mAnimationType; 567 if (mSceneTransitionStartedListener != null) { 568 try { 569 mSceneTransitionStartedListener.sendResult(null); 570 } catch (RemoteException e) { 571 } 572 } 573 mSceneTransitionStartedListener = otherOptions.mSceneTransitionStartedListener; 574 mDestSceneNames = otherOptions.mDestSceneNames; 575 mAnimationStartedListener = null; 576 break; 577 } 578 } 579 580 /** 581 * Returns the created options as a Bundle, which can be passed to 582 * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle) 583 * Context.startActivity(Intent, Bundle)} and related methods. 584 * Note that the returned Bundle is still owned by the ActivityOptions 585 * object; you must not modify it, but can supply it to the startActivity 586 * methods that take an options Bundle. 587 */ 588 public Bundle toBundle() { 589 Bundle b = new Bundle(); 590 if (mPackageName != null) { 591 b.putString(KEY_PACKAGE_NAME, mPackageName); 592 } 593 switch (mAnimationType) { 594 case ANIM_CUSTOM: 595 b.putInt(KEY_ANIM_TYPE, mAnimationType); 596 b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId); 597 b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId); 598 b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener 599 != null ? mAnimationStartedListener.asBinder() : null); 600 break; 601 case ANIM_SCALE_UP: 602 b.putInt(KEY_ANIM_TYPE, mAnimationType); 603 b.putInt(KEY_ANIM_START_X, mStartX); 604 b.putInt(KEY_ANIM_START_Y, mStartY); 605 b.putInt(KEY_ANIM_START_WIDTH, mStartWidth); 606 b.putInt(KEY_ANIM_START_HEIGHT, mStartHeight); 607 break; 608 case ANIM_THUMBNAIL_SCALE_UP: 609 case ANIM_THUMBNAIL_SCALE_DOWN: 610 b.putInt(KEY_ANIM_TYPE, mAnimationType); 611 b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail); 612 b.putInt(KEY_ANIM_START_X, mStartX); 613 b.putInt(KEY_ANIM_START_Y, mStartY); 614 b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener 615 != null ? mAnimationStartedListener.asBinder() : null); 616 break; 617 } 618 return b; 619 } 620} 621