AppTransition.java revision c554b77b7392b97e0f455d8276b739e16147d6df
1/* 2 * Copyright (C) 2011 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 com.android.server.wm; 18 19import android.content.Context; 20import android.content.res.Configuration; 21import android.graphics.Bitmap; 22import android.graphics.Rect; 23import android.os.Debug; 24import android.os.Handler; 25import android.os.IBinder; 26import android.os.IRemoteCallback; 27import android.util.Slog; 28import android.view.WindowManager; 29import android.view.animation.AlphaAnimation; 30import android.view.animation.Animation; 31import android.view.animation.AnimationSet; 32import android.view.animation.AnimationUtils; 33import android.view.animation.ClipRectAnimation; 34import android.view.animation.ClipRectLRAnimation; 35import android.view.animation.ClipRectTBAnimation; 36import android.view.animation.Interpolator; 37import android.view.animation.PathInterpolator; 38import android.view.animation.ScaleAnimation; 39import android.view.animation.TranslateAnimation; 40import android.view.animation.TranslateYAnimation; 41 42import com.android.internal.util.DumpUtils.Dump; 43import com.android.server.AttributeCache; 44import com.android.server.wm.WindowManagerService.H; 45 46import java.io.PrintWriter; 47import java.util.ArrayList; 48 49import static android.view.WindowManagerInternal.AppTransitionListener; 50import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation; 51import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation; 52import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation; 53import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation; 54import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation; 55import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation; 56import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation; 57import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation; 58import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation; 59import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation; 60import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation; 61import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation; 62import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation; 63import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation; 64import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation; 65import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation; 66import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation; 67import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation; 68import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation; 69import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; 70import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation; 71import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation; 72 73// State management of app transitions. When we are preparing for a 74// transition, mNextAppTransition will be the kind of transition to 75// perform or TRANSIT_NONE if we are not waiting. If we are waiting, 76// mOpeningApps and mClosingApps are the lists of tokens that will be 77// made visible or hidden at the next transition. 78public class AppTransition implements Dump { 79 private static final String TAG = "AppTransition"; 80 private static final boolean DEBUG_APP_TRANSITIONS = 81 WindowManagerService.DEBUG_APP_TRANSITIONS; 82 private static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_ANIM; 83 private static final int CLIP_REVEAL_TRANSLATION_Y_DP = 8; 84 85 /** Not set up for a transition. */ 86 public static final int TRANSIT_UNSET = -1; 87 /** No animation for transition. */ 88 public static final int TRANSIT_NONE = 0; 89 /** A window in a new activity is being opened on top of an existing one in the same task. */ 90 public static final int TRANSIT_ACTIVITY_OPEN = 6; 91 /** The window in the top-most activity is being closed to reveal the 92 * previous activity in the same task. */ 93 public static final int TRANSIT_ACTIVITY_CLOSE = 7; 94 /** A window in a new task is being opened on top of an existing one 95 * in another activity's task. */ 96 public static final int TRANSIT_TASK_OPEN = 8; 97 /** A window in the top-most activity is being closed to reveal the 98 * previous activity in a different task. */ 99 public static final int TRANSIT_TASK_CLOSE = 9; 100 /** A window in an existing task is being displayed on top of an existing one 101 * in another activity's task. */ 102 public static final int TRANSIT_TASK_TO_FRONT = 10; 103 /** A window in an existing task is being put below all other tasks. */ 104 public static final int TRANSIT_TASK_TO_BACK = 11; 105 /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that 106 * does, effectively closing the wallpaper. */ 107 public static final int TRANSIT_WALLPAPER_CLOSE = 12; 108 /** A window in a new activity that does have a wallpaper is being opened on one that didn't, 109 * effectively opening the wallpaper. */ 110 public static final int TRANSIT_WALLPAPER_OPEN = 13; 111 /** A window in a new activity is being opened on top of an existing one, and both are on top 112 * of the wallpaper. */ 113 public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14; 114 /** The window in the top-most activity is being closed to reveal the previous activity, and 115 * both are on top of the wallpaper. */ 116 public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15; 117 /** A window in a new task is being opened behind an existing one in another activity's task. 118 * The new window will show briefly and then be gone. */ 119 public static final int TRANSIT_TASK_OPEN_BEHIND = 16; 120 /** A window in a task is being animated in-place. */ 121 public static final int TRANSIT_TASK_IN_PLACE = 17; 122 123 /** Fraction of animation at which the recents thumbnail stays completely transparent */ 124 private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f; 125 /** Fraction of animation at which the recents thumbnail becomes completely transparent */ 126 private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f; 127 128 private static final int DEFAULT_APP_TRANSITION_DURATION = 336; 129 private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336; 130 private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336; 131 132 private final Context mContext; 133 private final Handler mH; 134 135 private int mNextAppTransition = TRANSIT_UNSET; 136 137 private static final int NEXT_TRANSIT_TYPE_NONE = 0; 138 private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1; 139 private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2; 140 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3; 141 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4; 142 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5; 143 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6; 144 private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7; 145 private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8; 146 private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; 147 148 // These are the possible states for the enter/exit activities during a thumbnail transition 149 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0; 150 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1; 151 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2; 152 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3; 153 154 private String mNextAppTransitionPackage; 155 private Bitmap mNextAppTransitionThumbnail; 156 // Used for thumbnail transitions. True if we're scaling up, false if scaling down 157 private boolean mNextAppTransitionScaleUp; 158 private IRemoteCallback mNextAppTransitionCallback; 159 private int mNextAppTransitionEnter; 160 private int mNextAppTransitionExit; 161 private int mNextAppTransitionInPlace; 162 private int mNextAppTransitionStartX; 163 private int mNextAppTransitionStartY; 164 private int mNextAppTransitionStartWidth; 165 private int mNextAppTransitionStartHeight; 166 private Rect mNextAppTransitionInsets = new Rect(); 167 168 private Rect mTmpFromClipRect = new Rect(); 169 private Rect mTmpToClipRect = new Rect(); 170 171 private final static int APP_STATE_IDLE = 0; 172 private final static int APP_STATE_READY = 1; 173 private final static int APP_STATE_RUNNING = 2; 174 private final static int APP_STATE_TIMEOUT = 3; 175 private int mAppTransitionState = APP_STATE_IDLE; 176 177 private final int mConfigShortAnimTime; 178 private final Interpolator mDecelerateInterpolator; 179 private final Interpolator mThumbnailFadeInInterpolator; 180 private final Interpolator mThumbnailFadeOutInterpolator; 181 private final Interpolator mLinearOutSlowInInterpolator; 182 private final Interpolator mFastOutLinearInInterpolator; 183 private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f); 184 185 /** Interpolator to be used for animations that respond directly to a touch */ 186 private final Interpolator mTouchResponseInterpolator = 187 new PathInterpolator(0.3f, 0f, 0.1f, 1f); 188 189 private final int mClipRevealTranslationY; 190 191 private int mCurrentUserId = 0; 192 193 private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>(); 194 195 AppTransition(Context context, Handler h) { 196 mContext = context; 197 mH = h; 198 mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, 199 com.android.internal.R.interpolator.linear_out_slow_in); 200 mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, 201 com.android.internal.R.interpolator.fast_out_linear_in); 202 mConfigShortAnimTime = context.getResources().getInteger( 203 com.android.internal.R.integer.config_shortAnimTime); 204 mDecelerateInterpolator = AnimationUtils.loadInterpolator(context, 205 com.android.internal.R.interpolator.decelerate_cubic); 206 mThumbnailFadeInInterpolator = new Interpolator() { 207 @Override 208 public float getInterpolation(float input) { 209 // Linear response for first fraction, then complete after that. 210 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) { 211 return 0f; 212 } 213 float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) / 214 (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION); 215 return mFastOutLinearInInterpolator.getInterpolation(t); 216 } 217 }; 218 mThumbnailFadeOutInterpolator = new Interpolator() { 219 @Override 220 public float getInterpolation(float input) { 221 // Linear response for first fraction, then complete after that. 222 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) { 223 float t = input / RECENTS_THUMBNAIL_FADEOUT_FRACTION; 224 return mLinearOutSlowInInterpolator.getInterpolation(t); 225 } 226 return 1f; 227 } 228 }; 229 mClipRevealTranslationY = (int) (CLIP_REVEAL_TRANSLATION_Y_DP 230 * mContext.getResources().getDisplayMetrics().density); 231 } 232 233 boolean isTransitionSet() { 234 return mNextAppTransition != TRANSIT_UNSET; 235 } 236 237 boolean isTransitionNone() { 238 return mNextAppTransition == TRANSIT_NONE; 239 } 240 241 boolean isTransitionEqual(int transit) { 242 return mNextAppTransition == transit; 243 } 244 245 int getAppTransition() { 246 return mNextAppTransition; 247 } 248 249 void setAppTransition(int transit) { 250 mNextAppTransition = transit; 251 } 252 253 boolean isReady() { 254 return mAppTransitionState == APP_STATE_READY 255 || mAppTransitionState == APP_STATE_TIMEOUT; 256 } 257 258 void setReady() { 259 mAppTransitionState = APP_STATE_READY; 260 } 261 262 boolean isRunning() { 263 return mAppTransitionState == APP_STATE_RUNNING; 264 } 265 266 void setIdle() { 267 mAppTransitionState = APP_STATE_IDLE; 268 } 269 270 boolean isTimeout() { 271 return mAppTransitionState == APP_STATE_TIMEOUT; 272 } 273 274 void setTimeout() { 275 mAppTransitionState = APP_STATE_TIMEOUT; 276 } 277 278 Bitmap getNextAppTransitionThumbnail() { 279 return mNextAppTransitionThumbnail; 280 } 281 282 /** Returns whether the next thumbnail transition is aspect scaled up. */ 283 boolean isNextThumbnailTransitionAspectScaled() { 284 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP || 285 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 286 } 287 288 /** Returns whether the next thumbnail transition is scaling up. */ 289 boolean isNextThumbnailTransitionScaleUp() { 290 return mNextAppTransitionScaleUp; 291 } 292 293 int getStartingX() { 294 return mNextAppTransitionStartX; 295 } 296 297 int getStartingY() { 298 return mNextAppTransitionStartY; 299 } 300 301 boolean prepare() { 302 if (!isRunning()) { 303 mAppTransitionState = APP_STATE_IDLE; 304 notifyAppTransitionPendingLocked(); 305 return true; 306 } 307 return false; 308 } 309 310 void goodToGo(AppWindowAnimator openingAppAnimator, AppWindowAnimator closingAppAnimator) { 311 mNextAppTransition = TRANSIT_UNSET; 312 mAppTransitionState = APP_STATE_RUNNING; 313 notifyAppTransitionStartingLocked( 314 openingAppAnimator != null ? openingAppAnimator.mAppToken.token : null, 315 closingAppAnimator != null ? closingAppAnimator.mAppToken.token : null, 316 openingAppAnimator != null ? openingAppAnimator.animation : null, 317 closingAppAnimator != null ? closingAppAnimator.animation : null); 318 } 319 320 void clear() { 321 mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; 322 mNextAppTransitionPackage = null; 323 mNextAppTransitionThumbnail = null; 324 } 325 326 void freeze() { 327 setAppTransition(AppTransition.TRANSIT_UNSET); 328 clear(); 329 setReady(); 330 notifyAppTransitionCancelledLocked(); 331 } 332 333 void registerListenerLocked(AppTransitionListener listener) { 334 mListeners.add(listener); 335 } 336 337 public void notifyAppTransitionFinishedLocked(IBinder token) { 338 for (int i = 0; i < mListeners.size(); i++) { 339 mListeners.get(i).onAppTransitionFinishedLocked(token); 340 } 341 } 342 343 private void notifyAppTransitionPendingLocked() { 344 for (int i = 0; i < mListeners.size(); i++) { 345 mListeners.get(i).onAppTransitionPendingLocked(); 346 } 347 } 348 349 private void notifyAppTransitionCancelledLocked() { 350 for (int i = 0; i < mListeners.size(); i++) { 351 mListeners.get(i).onAppTransitionCancelledLocked(); 352 } 353 } 354 355 private void notifyAppTransitionStartingLocked(IBinder openToken, 356 IBinder closeToken, Animation openAnimation, Animation closeAnimation) { 357 for (int i = 0; i < mListeners.size(); i++) { 358 mListeners.get(i).onAppTransitionStartingLocked(openToken, closeToken, openAnimation, 359 closeAnimation); 360 } 361 } 362 363 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) { 364 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg=" 365 + (lp != null ? lp.packageName : null) 366 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null)); 367 if (lp != null && lp.windowAnimations != 0) { 368 // If this is a system resource, don't try to load it from the 369 // application resources. It is nice to avoid loading application 370 // resources if we can. 371 String packageName = lp.packageName != null ? lp.packageName : "android"; 372 int resId = lp.windowAnimations; 373 if ((resId&0xFF000000) == 0x01000000) { 374 packageName = "android"; 375 } 376 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package=" 377 + packageName); 378 return AttributeCache.instance().get(packageName, resId, 379 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId); 380 } 381 return null; 382 } 383 384 private AttributeCache.Entry getCachedAnimations(String packageName, int resId) { 385 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package=" 386 + packageName + " resId=0x" + Integer.toHexString(resId)); 387 if (packageName != null) { 388 if ((resId&0xFF000000) == 0x01000000) { 389 packageName = "android"; 390 } 391 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package=" 392 + packageName); 393 return AttributeCache.instance().get(packageName, resId, 394 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId); 395 } 396 return null; 397 } 398 399 Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) { 400 int anim = 0; 401 Context context = mContext; 402 if (animAttr >= 0) { 403 AttributeCache.Entry ent = getCachedAnimations(lp); 404 if (ent != null) { 405 context = ent.context; 406 anim = ent.array.getResourceId(animAttr, 0); 407 } 408 } 409 if (anim != 0) { 410 return AnimationUtils.loadAnimation(context, anim); 411 } 412 return null; 413 } 414 415 Animation loadAnimationRes(WindowManager.LayoutParams lp, int resId) { 416 Context context = mContext; 417 if (resId >= 0) { 418 AttributeCache.Entry ent = getCachedAnimations(lp); 419 if (ent != null) { 420 context = ent.context; 421 } 422 return AnimationUtils.loadAnimation(context, resId); 423 } 424 return null; 425 } 426 427 private Animation loadAnimationRes(String packageName, int resId) { 428 int anim = 0; 429 Context context = mContext; 430 if (resId >= 0) { 431 AttributeCache.Entry ent = getCachedAnimations(packageName, resId); 432 if (ent != null) { 433 context = ent.context; 434 anim = resId; 435 } 436 } 437 if (anim != 0) { 438 return AnimationUtils.loadAnimation(context, anim); 439 } 440 return null; 441 } 442 443 /** 444 * Compute the pivot point for an animation that is scaling from a small 445 * rect on screen to a larger rect. The pivot point varies depending on 446 * the distance between the inner and outer edges on both sides. This 447 * function computes the pivot point for one dimension. 448 * @param startPos Offset from left/top edge of outer rectangle to 449 * left/top edge of inner rectangle. 450 * @param finalScale The scaling factor between the size of the outer 451 * and inner rectangles. 452 */ 453 private static float computePivot(int startPos, float finalScale) { 454 final float denom = finalScale-1; 455 if (Math.abs(denom) < .0001f) { 456 return startPos; 457 } 458 return -startPos / denom; 459 } 460 461 private Animation createScaleUpAnimationLocked(int transit, boolean enter, 462 int appWidth, int appHeight) { 463 Animation a = null; 464 if (enter) { 465 // Entering app zooms out from the center of the initial rect. 466 float scaleW = mNextAppTransitionStartWidth / (float) appWidth; 467 float scaleH = mNextAppTransitionStartHeight / (float) appHeight; 468 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1, 469 computePivot(mNextAppTransitionStartX, scaleW), 470 computePivot(mNextAppTransitionStartY, scaleH)); 471 scale.setInterpolator(mDecelerateInterpolator); 472 473 Animation alpha = new AlphaAnimation(0, 1); 474 alpha.setInterpolator(mThumbnailFadeOutInterpolator); 475 476 AnimationSet set = new AnimationSet(false); 477 set.addAnimation(scale); 478 set.addAnimation(alpha); 479 set.setDetachWallpaper(true); 480 a = set; 481 } else if (transit == TRANSIT_WALLPAPER_INTRA_OPEN || 482 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) { 483 // If we are on top of the wallpaper, we need an animation that 484 // correctly handles the wallpaper staying static behind all of 485 // the animated elements. To do this, will just have the existing 486 // element fade out. 487 a = new AlphaAnimation(1, 0); 488 a.setDetachWallpaper(true); 489 } else { 490 // For normal animations, the exiting element just holds in place. 491 a = new AlphaAnimation(1, 1); 492 } 493 494 // Pick the desired duration. If this is an inter-activity transition, 495 // it is the standard duration for that. Otherwise we use the longer 496 // task transition duration. 497 final long duration; 498 switch (transit) { 499 case TRANSIT_ACTIVITY_OPEN: 500 case TRANSIT_ACTIVITY_CLOSE: 501 duration = mConfigShortAnimTime; 502 break; 503 default: 504 duration = DEFAULT_APP_TRANSITION_DURATION; 505 break; 506 } 507 a.setDuration(duration); 508 a.setFillAfter(true); 509 a.setInterpolator(mDecelerateInterpolator); 510 a.initialize(appWidth, appHeight, appWidth, appHeight); 511 return a; 512 } 513 514 private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame) { 515 final Animation anim; 516 if (enter) { 517 // Reveal will expand and move faster in horizontal direction 518 519 final int appWidth = appFrame.width(); 520 final int appHeight = appFrame.height(); 521 522 float t = 0f; 523 if (appHeight > 0) { 524 t = (float) mNextAppTransitionStartY / appHeight; 525 } 526 int translationY = mClipRevealTranslationY 527 + (int)(appHeight / 7f * t); 528 529 int centerX = mNextAppTransitionStartX + mNextAppTransitionStartWidth / 2; 530 int centerY = mNextAppTransitionStartY + mNextAppTransitionStartHeight / 2; 531 532 // Clip third of the from size of launch icon, expand to full width/height 533 Animation clipAnimLR = new ClipRectLRAnimation( 534 centerX - mNextAppTransitionStartWidth / 3, 535 centerX + mNextAppTransitionStartWidth / 3, 536 0, appWidth); 537 clipAnimLR.setInterpolator(mClipHorizontalInterpolator); 538 clipAnimLR.setDuration((long) (DEFAULT_APP_TRANSITION_DURATION / 2.5f)); 539 Animation clipAnimTB = new ClipRectTBAnimation( 540 centerY - mNextAppTransitionStartHeight / 3 - translationY, 541 centerY + mNextAppTransitionStartHeight / 3 - translationY, 542 0, appHeight); 543 clipAnimTB.setInterpolator(mTouchResponseInterpolator); 544 clipAnimTB.setDuration(DEFAULT_APP_TRANSITION_DURATION); 545 546 TranslateYAnimation translateY = new TranslateYAnimation( 547 Animation.ABSOLUTE, translationY, Animation.ABSOLUTE, 0); 548 translateY.setInterpolator(mLinearOutSlowInInterpolator); 549 translateY.setDuration(DEFAULT_APP_TRANSITION_DURATION); 550 551 // Quick fade-in from icon to app window 552 final int alphaDuration = DEFAULT_APP_TRANSITION_DURATION / 4; 553 AlphaAnimation alpha = new AlphaAnimation(0.5f, 1); 554 alpha.setDuration(alphaDuration); 555 alpha.setInterpolator(mLinearOutSlowInInterpolator); 556 557 AnimationSet set = new AnimationSet(false); 558 set.addAnimation(clipAnimLR); 559 set.addAnimation(clipAnimTB); 560 set.addAnimation(translateY); 561 set.addAnimation(alpha); 562 set.initialize(appWidth, appHeight, appWidth, appHeight); 563 anim = set; 564 } else { 565 final long duration; 566 switch (transit) { 567 case TRANSIT_ACTIVITY_OPEN: 568 case TRANSIT_ACTIVITY_CLOSE: 569 duration = mConfigShortAnimTime; 570 break; 571 default: 572 duration = DEFAULT_APP_TRANSITION_DURATION; 573 break; 574 } 575 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN || 576 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) { 577 // If we are on top of the wallpaper, we need an animation that 578 // correctly handles the wallpaper staying static behind all of 579 // the animated elements. To do this, will just have the existing 580 // element fade out. 581 anim = new AlphaAnimation(1, 0); 582 anim.setDetachWallpaper(true); 583 } else { 584 // For normal animations, the exiting element just holds in place. 585 anim = new AlphaAnimation(1, 1); 586 } 587 anim.setInterpolator(mDecelerateInterpolator); 588 anim.setDuration(duration); 589 anim.setFillAfter(true); 590 } 591 return anim; 592 } 593 594 /** 595 * Prepares the specified animation with a standard duration, interpolator, etc. 596 */ 597 Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight, 598 int duration, Interpolator interpolator) { 599 if (duration > 0) { 600 a.setDuration(duration); 601 } 602 a.setFillAfter(true); 603 a.setInterpolator(interpolator); 604 a.initialize(appWidth, appHeight, appWidth, appHeight); 605 return a; 606 } 607 608 /** 609 * Prepares the specified animation with a standard duration, interpolator, etc. 610 */ 611 Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) { 612 // Pick the desired duration. If this is an inter-activity transition, 613 // it is the standard duration for that. Otherwise we use the longer 614 // task transition duration. 615 final int duration; 616 switch (transit) { 617 case TRANSIT_ACTIVITY_OPEN: 618 case TRANSIT_ACTIVITY_CLOSE: 619 duration = mConfigShortAnimTime; 620 break; 621 default: 622 duration = DEFAULT_APP_TRANSITION_DURATION; 623 break; 624 } 625 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration, 626 mDecelerateInterpolator); 627 } 628 629 /** 630 * Return the current thumbnail transition state. 631 */ 632 int getThumbnailTransitionState(boolean enter) { 633 if (enter) { 634 if (mNextAppTransitionScaleUp) { 635 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP; 636 } else { 637 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN; 638 } 639 } else { 640 if (mNextAppTransitionScaleUp) { 641 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP; 642 } else { 643 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN; 644 } 645 } 646 } 647 648 /** 649 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity 650 * when a thumbnail is specified with the activity options. 651 */ 652 Animation createThumbnailAspectScaleAnimationLocked(int appWidth, int appHeight, 653 int deviceWidth, int transit) { 654 Animation a; 655 final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); 656 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 657 final int thumbHeightI = mNextAppTransitionThumbnail.getHeight(); 658 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 659 660 float scaleW = deviceWidth / thumbWidth; 661 float unscaledWidth = deviceWidth; 662 float unscaledHeight = thumbHeight * scaleW; 663 float unscaledStartY = mNextAppTransitionStartY - (unscaledHeight - thumbHeight) / 2f; 664 if (mNextAppTransitionScaleUp) { 665 // Animation up from the thumbnail to the full screen 666 Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, 667 mNextAppTransitionStartX + (thumbWidth / 2f), 668 mNextAppTransitionStartY + (thumbHeight / 2f)); 669 scale.setInterpolator(mTouchResponseInterpolator); 670 scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); 671 Animation alpha = new AlphaAnimation(1, 0); 672 alpha.setInterpolator(mThumbnailFadeOutInterpolator); 673 alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION); 674 Animation translate = new TranslateAnimation(0, 0, 0, -unscaledStartY + 675 mNextAppTransitionInsets.top); 676 translate.setInterpolator(mTouchResponseInterpolator); 677 translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); 678 679 // This AnimationSet uses the Interpolators assigned above. 680 AnimationSet set = new AnimationSet(false); 681 set.addAnimation(scale); 682 set.addAnimation(alpha); 683 set.addAnimation(translate); 684 a = set; 685 } else { 686 // Animation down from the full screen to the thumbnail 687 Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, 688 mNextAppTransitionStartX + (thumbWidth / 2f), 689 mNextAppTransitionStartY + (thumbHeight / 2f)); 690 scale.setInterpolator(mTouchResponseInterpolator); 691 scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); 692 Animation alpha = new AlphaAnimation(0f, 1f); 693 alpha.setInterpolator(mThumbnailFadeInInterpolator); 694 alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION); 695 Animation translate = new TranslateAnimation(0, 0, -unscaledStartY + 696 mNextAppTransitionInsets.top, 0); 697 translate.setInterpolator(mTouchResponseInterpolator); 698 translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); 699 700 // This AnimationSet uses the Interpolators assigned above. 701 AnimationSet set = new AnimationSet(false); 702 set.addAnimation(scale); 703 set.addAnimation(alpha); 704 set.addAnimation(translate); 705 a = set; 706 707 } 708 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, 0, 709 mTouchResponseInterpolator); 710 } 711 712 /** 713 * This alternate animation is created when we are doing a thumbnail transition, for the 714 * activity that is leaving, and the activity that is entering. 715 */ 716 Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState, 717 int appWidth, int appHeight, int orientation, int transit, Rect containingFrame, 718 Rect contentInsets, boolean isFullScreen) { 719 Animation a; 720 final int thumbWidthI = mNextAppTransitionStartWidth; 721 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 722 final int thumbHeightI = mNextAppTransitionStartHeight; 723 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 724 725 // Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions 726 float scale = 1f; 727 int scaledTopDecor = 0; 728 729 switch (thumbTransitState) { 730 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: { 731 // App window scaling up to become full screen 732 if (orientation == Configuration.ORIENTATION_PORTRAIT) { 733 // In portrait, we scale the width and clip to the top/left square 734 scale = thumbWidth / appWidth; 735 scaledTopDecor = (int) (scale * contentInsets.top); 736 int unscaledThumbHeight = (int) (thumbHeight / scale); 737 mTmpFromClipRect.set(containingFrame); 738 if (isFullScreen) { 739 mTmpFromClipRect.top = contentInsets.top; 740 } 741 mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight); 742 mTmpToClipRect.set(containingFrame); 743 } else { 744 // In landscape, we scale the height and clip to the top/left square 745 scale = thumbHeight / (appHeight - contentInsets.top); 746 scaledTopDecor = (int) (scale * contentInsets.top); 747 int unscaledThumbWidth = (int) (thumbWidth / scale); 748 int unscaledThumbHeight = (int) (thumbHeight / scale); 749 mTmpFromClipRect.set(containingFrame); 750 if (isFullScreen) { 751 mTmpFromClipRect.top = contentInsets.top; 752 mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight); 753 } 754 mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth); 755 mTmpToClipRect.set(containingFrame); 756 } 757 mNextAppTransitionInsets.set(contentInsets); 758 759 Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1, 760 computePivot(mNextAppTransitionStartX, scale), 761 computePivot(mNextAppTransitionStartY, scale)); 762 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect); 763 Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0); 764 765 AnimationSet set = new AnimationSet(true); 766 set.addAnimation(clipAnim); 767 set.addAnimation(scaleAnim); 768 set.addAnimation(translateAnim); 769 a = set; 770 break; 771 } 772 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: { 773 // Previous app window during the scale up 774 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 775 // Fade out the source activity if we are animating to a wallpaper 776 // activity. 777 a = new AlphaAnimation(1, 0); 778 } else { 779 a = new AlphaAnimation(1, 1); 780 } 781 break; 782 } 783 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: { 784 // Target app window during the scale down 785 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 786 // Fade in the destination activity if we are animating from a wallpaper 787 // activity. 788 a = new AlphaAnimation(0, 1); 789 } else { 790 a = new AlphaAnimation(1, 1); 791 } 792 break; 793 } 794 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: { 795 // App window scaling down from full screen 796 if (orientation == Configuration.ORIENTATION_PORTRAIT) { 797 // In portrait, we scale the width and clip to the top/left square 798 scale = thumbWidth / appWidth; 799 scaledTopDecor = (int) (scale * contentInsets.top); 800 int unscaledThumbHeight = (int) (thumbHeight / scale); 801 mTmpFromClipRect.set(containingFrame); 802 mTmpToClipRect.set(containingFrame); 803 if (isFullScreen) { 804 mTmpToClipRect.top = contentInsets.top; 805 } 806 mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight); 807 } else { 808 // In landscape, we scale the height and clip to the top/left square 809 scale = thumbHeight / (appHeight - contentInsets.top); 810 scaledTopDecor = (int) (scale * contentInsets.top); 811 int unscaledThumbWidth = (int) (thumbWidth / scale); 812 int unscaledThumbHeight = (int) (thumbHeight / scale); 813 mTmpFromClipRect.set(containingFrame); 814 mTmpToClipRect.set(containingFrame); 815 if (isFullScreen) { 816 mTmpToClipRect.top = contentInsets.top; 817 mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight); 818 } 819 mTmpToClipRect.right = (mTmpToClipRect.left + unscaledThumbWidth); 820 } 821 mNextAppTransitionInsets.set(contentInsets); 822 823 Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale, 824 computePivot(mNextAppTransitionStartX, scale), 825 computePivot(mNextAppTransitionStartY, scale)); 826 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect); 827 Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor); 828 829 AnimationSet set = new AnimationSet(true); 830 set.addAnimation(clipAnim); 831 set.addAnimation(scaleAnim); 832 set.addAnimation(translateAnim); 833 834 a = set; 835 a.setZAdjustment(Animation.ZORDER_TOP); 836 break; 837 } 838 default: 839 throw new RuntimeException("Invalid thumbnail transition state"); 840 } 841 842 int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION, 843 THUMBNAIL_APP_TRANSITION_DURATION); 844 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration, 845 mTouchResponseInterpolator); 846 } 847 848 /** 849 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity 850 * when a thumbnail is specified with the activity options. 851 */ 852 Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit) { 853 Animation a; 854 final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); 855 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 856 final int thumbHeightI = mNextAppTransitionThumbnail.getHeight(); 857 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 858 859 if (mNextAppTransitionScaleUp) { 860 // Animation for the thumbnail zooming from its initial size to the full screen 861 float scaleW = appWidth / thumbWidth; 862 float scaleH = appHeight / thumbHeight; 863 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 864 computePivot(mNextAppTransitionStartX, 1 / scaleW), 865 computePivot(mNextAppTransitionStartY, 1 / scaleH)); 866 scale.setInterpolator(mDecelerateInterpolator); 867 868 Animation alpha = new AlphaAnimation(1, 0); 869 alpha.setInterpolator(mThumbnailFadeOutInterpolator); 870 871 // This AnimationSet uses the Interpolators assigned above. 872 AnimationSet set = new AnimationSet(false); 873 set.addAnimation(scale); 874 set.addAnimation(alpha); 875 a = set; 876 } else { 877 // Animation for the thumbnail zooming down from the full screen to its final size 878 float scaleW = appWidth / thumbWidth; 879 float scaleH = appHeight / thumbHeight; 880 a = new ScaleAnimation(scaleW, 1, scaleH, 1, 881 computePivot(mNextAppTransitionStartX, 1 / scaleW), 882 computePivot(mNextAppTransitionStartY, 1 / scaleH)); 883 } 884 885 return prepareThumbnailAnimation(a, appWidth, appHeight, transit); 886 } 887 888 /** 889 * This animation is created when we are doing a thumbnail transition, for the activity that is 890 * leaving, and the activity that is entering. 891 */ 892 Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth, 893 int appHeight, int transit) { 894 Animation a; 895 final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); 896 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 897 final int thumbHeightI = mNextAppTransitionThumbnail.getHeight(); 898 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 899 900 switch (thumbTransitState) { 901 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: { 902 // Entering app scales up with the thumbnail 903 float scaleW = thumbWidth / appWidth; 904 float scaleH = thumbHeight / appHeight; 905 a = new ScaleAnimation(scaleW, 1, scaleH, 1, 906 computePivot(mNextAppTransitionStartX, scaleW), 907 computePivot(mNextAppTransitionStartY, scaleH)); 908 break; 909 } 910 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: { 911 // Exiting app while the thumbnail is scaling up should fade or stay in place 912 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 913 // Fade out while bringing up selected activity. This keeps the 914 // current activity from showing through a launching wallpaper 915 // activity. 916 a = new AlphaAnimation(1, 0); 917 } else { 918 // noop animation 919 a = new AlphaAnimation(1, 1); 920 } 921 break; 922 } 923 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: { 924 // Entering the other app, it should just be visible while we scale the thumbnail 925 // down above it 926 a = new AlphaAnimation(1, 1); 927 break; 928 } 929 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: { 930 // Exiting the current app, the app should scale down with the thumbnail 931 float scaleW = thumbWidth / appWidth; 932 float scaleH = thumbHeight / appHeight; 933 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 934 computePivot(mNextAppTransitionStartX, scaleW), 935 computePivot(mNextAppTransitionStartY, scaleH)); 936 937 Animation alpha = new AlphaAnimation(1, 0); 938 939 AnimationSet set = new AnimationSet(true); 940 set.addAnimation(scale); 941 set.addAnimation(alpha); 942 set.setZAdjustment(Animation.ZORDER_TOP); 943 a = set; 944 break; 945 } 946 default: 947 throw new RuntimeException("Invalid thumbnail transition state"); 948 } 949 950 return prepareThumbnailAnimation(a, appWidth, appHeight, transit); 951 } 952 953 /** 954 * @return true if and only if the first frame of the transition can be skipped, i.e. the first 955 * frame of the transition doesn't change the visuals on screen, so we can start 956 * directly with the second one 957 */ 958 boolean canSkipFirstFrame() { 959 return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM 960 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE 961 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL; 962 } 963 964 Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, 965 int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets, 966 Rect appFrame, boolean isFullScreen, boolean isVoiceInteraction) { 967 Animation a; 968 if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN 969 || transit == TRANSIT_TASK_OPEN 970 || transit == TRANSIT_TASK_TO_FRONT)) { 971 a = loadAnimationRes(lp, enter 972 ? com.android.internal.R.anim.voice_activity_open_enter 973 : com.android.internal.R.anim.voice_activity_open_exit); 974 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 975 "applyAnimation voice:" 976 + " anim=" + a + " transit=" + appTransitionToString(transit) 977 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); 978 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE 979 || transit == TRANSIT_TASK_CLOSE 980 || transit == TRANSIT_TASK_TO_BACK)) { 981 a = loadAnimationRes(lp, enter 982 ? com.android.internal.R.anim.voice_activity_close_enter 983 : com.android.internal.R.anim.voice_activity_close_exit); 984 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 985 "applyAnimation voice:" 986 + " anim=" + a + " transit=" + appTransitionToString(transit) 987 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); 988 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { 989 a = loadAnimationRes(mNextAppTransitionPackage, enter ? 990 mNextAppTransitionEnter : mNextAppTransitionExit); 991 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 992 "applyAnimation:" 993 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM" 994 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 995 + " Callers=" + Debug.getCallers(3)); 996 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) { 997 a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace); 998 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 999 "applyAnimation:" 1000 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE" 1001 + " transit=" + appTransitionToString(transit) 1002 + " Callers=" + Debug.getCallers(3)); 1003 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) { 1004 a = createClipRevealAnimationLocked(transit, enter, appFrame); 1005 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1006 "applyAnimation:" 1007 + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL" 1008 + " Callers=" + Debug.getCallers(3)); 1009 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) { 1010 a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight); 1011 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1012 "applyAnimation:" 1013 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP" 1014 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1015 + " Callers=" + Debug.getCallers(3)); 1016 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP || 1017 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) { 1018 mNextAppTransitionScaleUp = 1019 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP); 1020 a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter), 1021 appWidth, appHeight, transit); 1022 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 1023 String animName = mNextAppTransitionScaleUp ? 1024 "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN"; 1025 Slog.v(TAG, "applyAnimation:" 1026 + " anim=" + a + " nextAppTransition=" + animName 1027 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1028 + " Callers=" + Debug.getCallers(3)); 1029 } 1030 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP || 1031 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) { 1032 mNextAppTransitionScaleUp = 1033 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP); 1034 a = createAspectScaledThumbnailEnterExitAnimationLocked( 1035 getThumbnailTransitionState(enter), appWidth, appHeight, orientation, 1036 transit, containingFrame, contentInsets, isFullScreen); 1037 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 1038 String animName = mNextAppTransitionScaleUp ? 1039 "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN"; 1040 Slog.v(TAG, "applyAnimation:" 1041 + " anim=" + a + " nextAppTransition=" + animName 1042 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1043 + " Callers=" + Debug.getCallers(3)); 1044 } 1045 } else { 1046 int animAttr = 0; 1047 switch (transit) { 1048 case TRANSIT_ACTIVITY_OPEN: 1049 animAttr = enter 1050 ? WindowAnimation_activityOpenEnterAnimation 1051 : WindowAnimation_activityOpenExitAnimation; 1052 break; 1053 case TRANSIT_ACTIVITY_CLOSE: 1054 animAttr = enter 1055 ? WindowAnimation_activityCloseEnterAnimation 1056 : WindowAnimation_activityCloseExitAnimation; 1057 break; 1058 case TRANSIT_TASK_OPEN: 1059 animAttr = enter 1060 ? WindowAnimation_taskOpenEnterAnimation 1061 : WindowAnimation_taskOpenExitAnimation; 1062 break; 1063 case TRANSIT_TASK_CLOSE: 1064 animAttr = enter 1065 ? WindowAnimation_taskCloseEnterAnimation 1066 : WindowAnimation_taskCloseExitAnimation; 1067 break; 1068 case TRANSIT_TASK_TO_FRONT: 1069 animAttr = enter 1070 ? WindowAnimation_taskToFrontEnterAnimation 1071 : WindowAnimation_taskToFrontExitAnimation; 1072 break; 1073 case TRANSIT_TASK_TO_BACK: 1074 animAttr = enter 1075 ? WindowAnimation_taskToBackEnterAnimation 1076 : WindowAnimation_taskToBackExitAnimation; 1077 break; 1078 case TRANSIT_WALLPAPER_OPEN: 1079 animAttr = enter 1080 ? WindowAnimation_wallpaperOpenEnterAnimation 1081 : WindowAnimation_wallpaperOpenExitAnimation; 1082 break; 1083 case TRANSIT_WALLPAPER_CLOSE: 1084 animAttr = enter 1085 ? WindowAnimation_wallpaperCloseEnterAnimation 1086 : WindowAnimation_wallpaperCloseExitAnimation; 1087 break; 1088 case TRANSIT_WALLPAPER_INTRA_OPEN: 1089 animAttr = enter 1090 ? WindowAnimation_wallpaperIntraOpenEnterAnimation 1091 : WindowAnimation_wallpaperIntraOpenExitAnimation; 1092 break; 1093 case TRANSIT_WALLPAPER_INTRA_CLOSE: 1094 animAttr = enter 1095 ? WindowAnimation_wallpaperIntraCloseEnterAnimation 1096 : WindowAnimation_wallpaperIntraCloseExitAnimation; 1097 break; 1098 case TRANSIT_TASK_OPEN_BEHIND: 1099 animAttr = enter 1100 ? WindowAnimation_launchTaskBehindSourceAnimation 1101 : WindowAnimation_launchTaskBehindTargetAnimation; 1102 } 1103 a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null; 1104 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1105 "applyAnimation:" 1106 + " anim=" + a 1107 + " animAttr=0x" + Integer.toHexString(animAttr) 1108 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1109 + " Callers=" + Debug.getCallers(3)); 1110 } 1111 return a; 1112 } 1113 1114 void postAnimationCallback() { 1115 if (mNextAppTransitionCallback != null) { 1116 mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, mNextAppTransitionCallback)); 1117 mNextAppTransitionCallback = null; 1118 } 1119 } 1120 1121 void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, 1122 IRemoteCallback startedCallback) { 1123 if (isTransitionSet()) { 1124 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM; 1125 mNextAppTransitionPackage = packageName; 1126 mNextAppTransitionThumbnail = null; 1127 mNextAppTransitionEnter = enterAnim; 1128 mNextAppTransitionExit = exitAnim; 1129 postAnimationCallback(); 1130 mNextAppTransitionCallback = startedCallback; 1131 } else { 1132 postAnimationCallback(); 1133 } 1134 } 1135 1136 void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, 1137 int startHeight) { 1138 if (isTransitionSet()) { 1139 mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP; 1140 mNextAppTransitionPackage = null; 1141 mNextAppTransitionThumbnail = null; 1142 mNextAppTransitionStartX = startX; 1143 mNextAppTransitionStartY = startY; 1144 mNextAppTransitionStartWidth = startWidth; 1145 mNextAppTransitionStartHeight = startHeight; 1146 postAnimationCallback(); 1147 mNextAppTransitionCallback = null; 1148 } 1149 } 1150 1151 void overridePendingAppTransitionClipReveal(int startX, int startY, 1152 int startWidth, int startHeight) { 1153 if (isTransitionSet()) { 1154 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL; 1155 mNextAppTransitionStartX = startX; 1156 mNextAppTransitionStartY = startY; 1157 mNextAppTransitionStartWidth = startWidth; 1158 mNextAppTransitionStartHeight = startHeight; 1159 postAnimationCallback(); 1160 mNextAppTransitionCallback = null; 1161 } 1162 } 1163 1164 void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY, 1165 IRemoteCallback startedCallback, boolean scaleUp) { 1166 if (isTransitionSet()) { 1167 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP 1168 : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN; 1169 mNextAppTransitionPackage = null; 1170 mNextAppTransitionThumbnail = srcThumb; 1171 mNextAppTransitionScaleUp = scaleUp; 1172 mNextAppTransitionStartX = startX; 1173 mNextAppTransitionStartY = startY; 1174 postAnimationCallback(); 1175 mNextAppTransitionCallback = startedCallback; 1176 } else { 1177 postAnimationCallback(); 1178 } 1179 } 1180 1181 void overridePendingAppTransitionAspectScaledThumb(Bitmap srcThumb, int startX, int startY, 1182 int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) { 1183 if (isTransitionSet()) { 1184 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP 1185 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 1186 mNextAppTransitionPackage = null; 1187 mNextAppTransitionThumbnail = srcThumb; 1188 mNextAppTransitionScaleUp = scaleUp; 1189 mNextAppTransitionStartX = startX; 1190 mNextAppTransitionStartY = startY; 1191 mNextAppTransitionStartWidth = targetWidth; 1192 mNextAppTransitionStartHeight = targetHeight; 1193 postAnimationCallback(); 1194 mNextAppTransitionCallback = startedCallback; 1195 } else { 1196 postAnimationCallback(); 1197 } 1198 } 1199 1200 void overrideInPlaceAppTransition(String packageName, int anim) { 1201 if (isTransitionSet()) { 1202 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE; 1203 mNextAppTransitionPackage = packageName; 1204 mNextAppTransitionInPlace = anim; 1205 } else { 1206 postAnimationCallback(); 1207 } 1208 } 1209 1210 @Override 1211 public String toString() { 1212 return "mNextAppTransition=" + appTransitionToString(mNextAppTransition); 1213 } 1214 1215 /** 1216 * Returns the human readable name of a window transition. 1217 * 1218 * @param transition The window transition. 1219 * @return The transition symbolic name. 1220 */ 1221 public static String appTransitionToString(int transition) { 1222 switch (transition) { 1223 case TRANSIT_UNSET: { 1224 return "TRANSIT_UNSET"; 1225 } 1226 case TRANSIT_NONE: { 1227 return "TRANSIT_NONE"; 1228 } 1229 case TRANSIT_ACTIVITY_OPEN: { 1230 return "TRANSIT_ACTIVITY_OPEN"; 1231 } 1232 case TRANSIT_ACTIVITY_CLOSE: { 1233 return "TRANSIT_ACTIVITY_CLOSE"; 1234 } 1235 case TRANSIT_TASK_OPEN: { 1236 return "TRANSIT_TASK_OPEN"; 1237 } 1238 case TRANSIT_TASK_CLOSE: { 1239 return "TRANSIT_TASK_CLOSE"; 1240 } 1241 case TRANSIT_TASK_TO_FRONT: { 1242 return "TRANSIT_TASK_TO_FRONT"; 1243 } 1244 case TRANSIT_TASK_TO_BACK: { 1245 return "TRANSIT_TASK_TO_BACK"; 1246 } 1247 case TRANSIT_WALLPAPER_CLOSE: { 1248 return "TRANSIT_WALLPAPER_CLOSE"; 1249 } 1250 case TRANSIT_WALLPAPER_OPEN: { 1251 return "TRANSIT_WALLPAPER_OPEN"; 1252 } 1253 case TRANSIT_WALLPAPER_INTRA_OPEN: { 1254 return "TRANSIT_WALLPAPER_INTRA_OPEN"; 1255 } 1256 case TRANSIT_WALLPAPER_INTRA_CLOSE: { 1257 return "TRANSIT_WALLPAPER_INTRA_CLOSE"; 1258 } 1259 case TRANSIT_TASK_OPEN_BEHIND: { 1260 return "TRANSIT_TASK_OPEN_BEHIND"; 1261 } 1262 default: { 1263 return "<UNKNOWN>"; 1264 } 1265 } 1266 } 1267 1268 private String appStateToString() { 1269 switch (mAppTransitionState) { 1270 case APP_STATE_IDLE: 1271 return "APP_STATE_IDLE"; 1272 case APP_STATE_READY: 1273 return "APP_STATE_READY"; 1274 case APP_STATE_RUNNING: 1275 return "APP_STATE_RUNNING"; 1276 case APP_STATE_TIMEOUT: 1277 return "APP_STATE_TIMEOUT"; 1278 default: 1279 return "unknown state=" + mAppTransitionState; 1280 } 1281 } 1282 1283 private String transitTypeToString() { 1284 switch (mNextAppTransitionType) { 1285 case NEXT_TRANSIT_TYPE_NONE: 1286 return "NEXT_TRANSIT_TYPE_NONE"; 1287 case NEXT_TRANSIT_TYPE_CUSTOM: 1288 return "NEXT_TRANSIT_TYPE_CUSTOM"; 1289 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE: 1290 return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE"; 1291 case NEXT_TRANSIT_TYPE_SCALE_UP: 1292 return "NEXT_TRANSIT_TYPE_SCALE_UP"; 1293 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: 1294 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP"; 1295 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: 1296 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN"; 1297 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP: 1298 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP"; 1299 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: 1300 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN"; 1301 default: 1302 return "unknown type=" + mNextAppTransitionType; 1303 } 1304 } 1305 1306 @Override 1307 public void dump(PrintWriter pw, String prefix) { 1308 pw.print(prefix); pw.println(this); 1309 pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString()); 1310 if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) { 1311 pw.print(prefix); pw.print("mNextAppTransitionType="); 1312 pw.println(transitTypeToString()); 1313 } 1314 switch (mNextAppTransitionType) { 1315 case NEXT_TRANSIT_TYPE_CUSTOM: 1316 pw.print(prefix); pw.print("mNextAppTransitionPackage="); 1317 pw.println(mNextAppTransitionPackage); 1318 pw.print(prefix); pw.print("mNextAppTransitionEnter=0x"); 1319 pw.print(Integer.toHexString(mNextAppTransitionEnter)); 1320 pw.print(" mNextAppTransitionExit=0x"); 1321 pw.println(Integer.toHexString(mNextAppTransitionExit)); 1322 break; 1323 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE: 1324 pw.print(prefix); pw.print("mNextAppTransitionPackage="); 1325 pw.println(mNextAppTransitionPackage); 1326 pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x"); 1327 pw.print(Integer.toHexString(mNextAppTransitionInPlace)); 1328 break; 1329 case NEXT_TRANSIT_TYPE_SCALE_UP: 1330 pw.print(prefix); pw.print("mNextAppTransitionStartX="); 1331 pw.print(mNextAppTransitionStartX); 1332 pw.print(" mNextAppTransitionStartY="); 1333 pw.println(mNextAppTransitionStartY); 1334 pw.print(prefix); pw.print("mNextAppTransitionStartWidth="); 1335 pw.print(mNextAppTransitionStartWidth); 1336 pw.print(" mNextAppTransitionStartHeight="); 1337 pw.println(mNextAppTransitionStartHeight); 1338 break; 1339 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: 1340 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: 1341 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP: 1342 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: 1343 pw.print(prefix); pw.print("mNextAppTransitionThumbnail="); 1344 pw.print(mNextAppTransitionThumbnail); 1345 pw.print(" mNextAppTransitionStartX="); 1346 pw.print(mNextAppTransitionStartX); 1347 pw.print(" mNextAppTransitionStartY="); 1348 pw.println(mNextAppTransitionStartY); 1349 pw.print(prefix); pw.print("mNextAppTransitionStartWidth="); 1350 pw.print(mNextAppTransitionStartWidth); 1351 pw.print(" mNextAppTransitionStartHeight="); 1352 pw.println(mNextAppTransitionStartHeight); 1353 pw.print(prefix); pw.print("mNextAppTransitionScaleUp="); 1354 pw.println(mNextAppTransitionScaleUp); 1355 break; 1356 } 1357 if (mNextAppTransitionCallback != null) { 1358 pw.print(prefix); pw.print("mNextAppTransitionCallback="); 1359 pw.println(mNextAppTransitionCallback); 1360 } 1361 } 1362 1363 public void setCurrentUser(int newUserId) { 1364 mCurrentUserId = newUserId; 1365 } 1366} 1367