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