AppTransition.java revision ed410b692820783e5677fd174693588ddc528414
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 static android.view.WindowManagerInternal.AppTransitionListener; 20import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation; 21import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation; 22import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation; 23import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation; 24import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation; 25import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation; 26import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation; 27import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation; 28import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation; 29import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation; 30import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation; 31import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation; 32import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation; 33import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation; 34import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation; 35import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation; 36import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation; 37import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation; 38import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation; 39import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; 40import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation; 41import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation; 42import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START; 43import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; 44import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; 45import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 46import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 47import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; 48import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE; 49import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; 50 51import android.annotation.Nullable; 52import android.content.Context; 53import android.content.res.Configuration; 54import android.graphics.Bitmap; 55import android.graphics.Path; 56import android.graphics.Rect; 57import android.os.Binder; 58import android.os.Debug; 59import android.os.IBinder; 60import android.os.IRemoteCallback; 61import android.os.RemoteException; 62import android.os.SystemProperties; 63import android.util.ArraySet; 64import android.util.Slog; 65import android.util.SparseArray; 66import android.view.AppTransitionAnimationSpec; 67import android.view.IAppTransitionAnimationSpecsFuture; 68import android.view.WindowManager; 69import android.view.animation.AlphaAnimation; 70import android.view.animation.Animation; 71import android.view.animation.AnimationSet; 72import android.view.animation.AnimationUtils; 73import android.view.animation.ClipRectAnimation; 74import android.view.animation.Interpolator; 75import android.view.animation.PathInterpolator; 76import android.view.animation.ScaleAnimation; 77import android.view.animation.TranslateAnimation; 78 79import com.android.internal.util.DumpUtils.Dump; 80import com.android.server.AttributeCache; 81import com.android.server.wm.WindowManagerService.H; 82import com.android.server.wm.animation.ClipRectLRAnimation; 83import com.android.server.wm.animation.ClipRectTBAnimation; 84import com.android.server.wm.animation.CurvedTranslateAnimation; 85 86import java.io.PrintWriter; 87import java.util.ArrayList; 88import java.util.concurrent.ExecutorService; 89import java.util.concurrent.Executors; 90 91// State management of app transitions. When we are preparing for a 92// transition, mNextAppTransition will be the kind of transition to 93// perform or TRANSIT_NONE if we are not waiting. If we are waiting, 94// mOpeningApps and mClosingApps are the lists of tokens that will be 95// made visible or hidden at the next transition. 96public class AppTransition implements Dump { 97 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransition" : TAG_WM; 98 private static final int CLIP_REVEAL_TRANSLATION_Y_DP = 8; 99 100 /** Not set up for a transition. */ 101 public static final int TRANSIT_UNSET = -1; 102 /** No animation for transition. */ 103 public static final int TRANSIT_NONE = 0; 104 /** A window in a new activity is being opened on top of an existing one in the same task. */ 105 public static final int TRANSIT_ACTIVITY_OPEN = 6; 106 /** The window in the top-most activity is being closed to reveal the 107 * previous activity in the same task. */ 108 public static final int TRANSIT_ACTIVITY_CLOSE = 7; 109 /** A window in a new task is being opened on top of an existing one 110 * in another activity's task. */ 111 public static final int TRANSIT_TASK_OPEN = 8; 112 /** A window in the top-most activity is being closed to reveal the 113 * previous activity in a different task. */ 114 public static final int TRANSIT_TASK_CLOSE = 9; 115 /** A window in an existing task is being displayed on top of an existing one 116 * in another activity's task. */ 117 public static final int TRANSIT_TASK_TO_FRONT = 10; 118 /** A window in an existing task is being put below all other tasks. */ 119 public static final int TRANSIT_TASK_TO_BACK = 11; 120 /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that 121 * does, effectively closing the wallpaper. */ 122 public static final int TRANSIT_WALLPAPER_CLOSE = 12; 123 /** A window in a new activity that does have a wallpaper is being opened on one that didn't, 124 * effectively opening the wallpaper. */ 125 public static final int TRANSIT_WALLPAPER_OPEN = 13; 126 /** A window in a new activity is being opened on top of an existing one, and both are on top 127 * of the wallpaper. */ 128 public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14; 129 /** The window in the top-most activity is being closed to reveal the previous activity, and 130 * both are on top of the wallpaper. */ 131 public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15; 132 /** A window in a new task is being opened behind an existing one in another activity's task. 133 * The new window will show briefly and then be gone. */ 134 public static final int TRANSIT_TASK_OPEN_BEHIND = 16; 135 /** A window in a task is being animated in-place. */ 136 public static final int TRANSIT_TASK_IN_PLACE = 17; 137 /** An activity is being relaunched (e.g. due to configuration change). */ 138 public static final int TRANSIT_ACTIVITY_RELAUNCH = 18; 139 /** A task is being docked from recents. */ 140 public static final int TRANSIT_DOCK_TASK_FROM_RECENTS = 19; 141 /** Keyguard is going away */ 142 public static final int TRANSIT_KEYGUARD_GOING_AWAY = 20; 143 /** Keyguard is going away with showing an activity behind that requests wallpaper */ 144 public static final int TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21; 145 /** Keyguard is being occluded */ 146 public static final int TRANSIT_KEYGUARD_OCCLUDE = 22; 147 /** Keyguard is being unoccluded */ 148 public static final int TRANSIT_KEYGUARD_UNOCCLUDE = 23; 149 150 /** Transition flag: Keyguard is going away, but keeping the notification shade open */ 151 public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE = 0x1; 152 /** Transition flag: Keyguard is going away, but doesn't want an animation for it */ 153 public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION = 0x2; 154 /** Transition flag: Keyguard is going away while it was showing the system wallpaper. */ 155 public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER = 0x4; 156 157 /** Fraction of animation at which the recents thumbnail stays completely transparent */ 158 private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f; 159 /** Fraction of animation at which the recents thumbnail becomes completely transparent */ 160 private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f; 161 162 static final int DEFAULT_APP_TRANSITION_DURATION = 336; 163 164 /** Interpolator to be used for animations that respond directly to a touch */ 165 static final Interpolator TOUCH_RESPONSE_INTERPOLATOR = 166 new PathInterpolator(0.3f, 0f, 0.1f, 1f); 167 168 private static final Interpolator THUMBNAIL_DOCK_INTERPOLATOR = 169 new PathInterpolator(0.85f, 0f, 1f, 1f); 170 171 /** 172 * Maximum duration for the clip reveal animation. This is used when there is a lot of movement 173 * involved, to make it more understandable. 174 */ 175 private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420; 176 private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336; 177 private static final long APP_TRANSITION_TIMEOUT_MS = 5000; 178 179 private final Context mContext; 180 private final WindowManagerService mService; 181 182 private int mNextAppTransition = TRANSIT_UNSET; 183 private int mNextAppTransitionFlags = 0; 184 private int mLastUsedAppTransition = TRANSIT_UNSET; 185 private String mLastOpeningApp; 186 private String mLastClosingApp; 187 188 private static final int NEXT_TRANSIT_TYPE_NONE = 0; 189 private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1; 190 private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2; 191 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3; 192 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4; 193 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5; 194 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6; 195 private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7; 196 private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8; 197 private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; 198 199 // These are the possible states for the enter/exit activities during a thumbnail transition 200 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0; 201 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1; 202 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2; 203 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3; 204 205 private String mNextAppTransitionPackage; 206 // Used for thumbnail transitions. True if we're scaling up, false if scaling down 207 private boolean mNextAppTransitionScaleUp; 208 private IRemoteCallback mNextAppTransitionCallback; 209 private IRemoteCallback mNextAppTransitionFutureCallback; 210 private IRemoteCallback mAnimationFinishedCallback; 211 private int mNextAppTransitionEnter; 212 private int mNextAppTransitionExit; 213 private int mNextAppTransitionInPlace; 214 215 // Keyed by task id. 216 private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs 217 = new SparseArray<>(); 218 private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture; 219 private boolean mNextAppTransitionAnimationsSpecsPending; 220 private AppTransitionAnimationSpec mDefaultNextAppTransitionAnimationSpec; 221 222 private Rect mNextAppTransitionInsets = new Rect(); 223 224 private Rect mTmpFromClipRect = new Rect(); 225 private Rect mTmpToClipRect = new Rect(); 226 227 private final Rect mTmpRect = new Rect(); 228 229 private final static int APP_STATE_IDLE = 0; 230 private final static int APP_STATE_READY = 1; 231 private final static int APP_STATE_RUNNING = 2; 232 private final static int APP_STATE_TIMEOUT = 3; 233 private int mAppTransitionState = APP_STATE_IDLE; 234 235 private final int mConfigShortAnimTime; 236 private final Interpolator mDecelerateInterpolator; 237 private final Interpolator mThumbnailFadeInInterpolator; 238 private final Interpolator mThumbnailFadeOutInterpolator; 239 private final Interpolator mLinearOutSlowInInterpolator; 240 private final Interpolator mFastOutLinearInInterpolator; 241 private final Interpolator mFastOutSlowInInterpolator; 242 private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f); 243 244 private final int mClipRevealTranslationY; 245 246 private int mCurrentUserId = 0; 247 private long mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION; 248 249 private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>(); 250 private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor(); 251 252 private int mLastClipRevealMaxTranslation; 253 private boolean mLastHadClipReveal; 254 private boolean mProlongedAnimationsEnded; 255 256 private final boolean mGridLayoutRecentsEnabled; 257 258 AppTransition(Context context, WindowManagerService service) { 259 mContext = context; 260 mService = service; 261 mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, 262 com.android.internal.R.interpolator.linear_out_slow_in); 263 mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, 264 com.android.internal.R.interpolator.fast_out_linear_in); 265 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, 266 com.android.internal.R.interpolator.fast_out_slow_in); 267 mConfigShortAnimTime = context.getResources().getInteger( 268 com.android.internal.R.integer.config_shortAnimTime); 269 mDecelerateInterpolator = AnimationUtils.loadInterpolator(context, 270 com.android.internal.R.interpolator.decelerate_cubic); 271 mThumbnailFadeInInterpolator = new Interpolator() { 272 @Override 273 public float getInterpolation(float input) { 274 // Linear response for first fraction, then complete after that. 275 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) { 276 return 0f; 277 } 278 float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) / 279 (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION); 280 return mFastOutLinearInInterpolator.getInterpolation(t); 281 } 282 }; 283 mThumbnailFadeOutInterpolator = new Interpolator() { 284 @Override 285 public float getInterpolation(float input) { 286 // Linear response for first fraction, then complete after that. 287 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) { 288 float t = input / RECENTS_THUMBNAIL_FADEOUT_FRACTION; 289 return mLinearOutSlowInInterpolator.getInterpolation(t); 290 } 291 return 1f; 292 } 293 }; 294 mClipRevealTranslationY = (int) (CLIP_REVEAL_TRANSLATION_Y_DP 295 * mContext.getResources().getDisplayMetrics().density); 296 mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false); 297 } 298 299 boolean isTransitionSet() { 300 return mNextAppTransition != TRANSIT_UNSET; 301 } 302 303 boolean isTransitionEqual(int transit) { 304 return mNextAppTransition == transit; 305 } 306 307 int getAppTransition() { 308 return mNextAppTransition; 309 } 310 311 private void setAppTransition(int transit, int flags) { 312 mNextAppTransition = transit; 313 mNextAppTransitionFlags |= flags; 314 setLastAppTransition(TRANSIT_UNSET, null, null); 315 } 316 317 void setLastAppTransition(int transit, AppWindowToken openingApp, AppWindowToken closingApp) { 318 mLastUsedAppTransition = transit; 319 mLastOpeningApp = "" + openingApp; 320 mLastClosingApp = "" + closingApp; 321 } 322 323 boolean isReady() { 324 return mAppTransitionState == APP_STATE_READY 325 || mAppTransitionState == APP_STATE_TIMEOUT; 326 } 327 328 void setReady() { 329 mAppTransitionState = APP_STATE_READY; 330 fetchAppTransitionSpecsFromFuture(); 331 } 332 333 boolean isRunning() { 334 return mAppTransitionState == APP_STATE_RUNNING; 335 } 336 337 void setIdle() { 338 mAppTransitionState = APP_STATE_IDLE; 339 } 340 341 boolean isTimeout() { 342 return mAppTransitionState == APP_STATE_TIMEOUT; 343 } 344 345 void setTimeout() { 346 mAppTransitionState = APP_STATE_TIMEOUT; 347 } 348 349 Bitmap getAppTransitionThumbnailHeader(int taskId) { 350 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId); 351 if (spec == null) { 352 spec = mDefaultNextAppTransitionAnimationSpec; 353 } 354 return spec != null ? spec.bitmap : null; 355 } 356 357 /** Returns whether the next thumbnail transition is aspect scaled up. */ 358 boolean isNextThumbnailTransitionAspectScaled() { 359 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP || 360 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 361 } 362 363 /** Returns whether the next thumbnail transition is scaling up. */ 364 boolean isNextThumbnailTransitionScaleUp() { 365 return mNextAppTransitionScaleUp; 366 } 367 368 boolean isNextAppTransitionThumbnailUp() { 369 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP || 370 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP; 371 } 372 373 boolean isNextAppTransitionThumbnailDown() { 374 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN || 375 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 376 } 377 378 /** 379 * @return true if and only if we are currently fetching app transition specs from the future 380 * passed into {@link #overridePendingAppTransitionMultiThumbFuture} 381 */ 382 boolean isFetchingAppTransitionsSpecs() { 383 return mNextAppTransitionAnimationsSpecsPending; 384 } 385 386 private boolean prepare() { 387 if (!isRunning()) { 388 mAppTransitionState = APP_STATE_IDLE; 389 notifyAppTransitionPendingLocked(); 390 mLastHadClipReveal = false; 391 mLastClipRevealMaxTranslation = 0; 392 mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION; 393 return true; 394 } 395 return false; 396 } 397 398 /** 399 * @return bit-map of WindowManagerPolicy#FINISH_LAYOUT_REDO_* to indicate whether another 400 * layout pass needs to be done 401 */ 402 int goodToGo(int transit, AppWindowAnimator topOpeningAppAnimator, 403 AppWindowAnimator topClosingAppAnimator, ArraySet<AppWindowToken> openingApps, 404 ArraySet<AppWindowToken> closingApps) { 405 mNextAppTransition = TRANSIT_UNSET; 406 mNextAppTransitionFlags = 0; 407 mAppTransitionState = APP_STATE_RUNNING; 408 int redoLayout = notifyAppTransitionStartingLocked(transit, 409 topOpeningAppAnimator != null ? topOpeningAppAnimator.mAppToken.token : null, 410 topClosingAppAnimator != null ? topClosingAppAnimator.mAppToken.token : null, 411 topOpeningAppAnimator != null ? topOpeningAppAnimator.animation : null, 412 topClosingAppAnimator != null ? topClosingAppAnimator.animation : null); 413 mService.getDefaultDisplayContentLocked().getDockedDividerController() 414 .notifyAppTransitionStarting(openingApps, transit); 415 416 // Prolong the start for the transition when docking a task from recents, unless recents 417 // ended it already then we don't need to wait. 418 if (transit == TRANSIT_DOCK_TASK_FROM_RECENTS && !mProlongedAnimationsEnded) { 419 for (int i = openingApps.size() - 1; i >= 0; i--) { 420 final AppWindowAnimator appAnimator = openingApps.valueAt(i).mAppAnimator; 421 appAnimator.startProlongAnimation(PROLONG_ANIMATION_AT_START); 422 } 423 } 424 return redoLayout; 425 } 426 427 /** 428 * Let the transitions manager know that the somebody wanted to end the prolonged animations. 429 */ 430 void notifyProlongedAnimationsEnded() { 431 mProlongedAnimationsEnded = true; 432 } 433 434 void clear() { 435 mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; 436 mNextAppTransitionPackage = null; 437 mNextAppTransitionAnimationsSpecs.clear(); 438 mNextAppTransitionAnimationsSpecsFuture = null; 439 mDefaultNextAppTransitionAnimationSpec = null; 440 mAnimationFinishedCallback = null; 441 mProlongedAnimationsEnded = false; 442 } 443 444 void freeze() { 445 final int transit = mNextAppTransition; 446 setAppTransition(AppTransition.TRANSIT_UNSET, 0 /* flags */); 447 clear(); 448 setReady(); 449 notifyAppTransitionCancelledLocked(transit); 450 } 451 452 void registerListenerLocked(AppTransitionListener listener) { 453 mListeners.add(listener); 454 } 455 456 public void notifyAppTransitionFinishedLocked(IBinder token) { 457 for (int i = 0; i < mListeners.size(); i++) { 458 mListeners.get(i).onAppTransitionFinishedLocked(token); 459 } 460 } 461 462 private void notifyAppTransitionPendingLocked() { 463 for (int i = 0; i < mListeners.size(); i++) { 464 mListeners.get(i).onAppTransitionPendingLocked(); 465 } 466 } 467 468 private void notifyAppTransitionCancelledLocked(int transit) { 469 for (int i = 0; i < mListeners.size(); i++) { 470 mListeners.get(i).onAppTransitionCancelledLocked(transit); 471 } 472 } 473 474 private int notifyAppTransitionStartingLocked(int transit, IBinder openToken, 475 IBinder closeToken, Animation openAnimation, Animation closeAnimation) { 476 int redoLayout = 0; 477 for (int i = 0; i < mListeners.size(); i++) { 478 redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(transit, openToken, 479 closeToken, openAnimation, closeAnimation); 480 } 481 return redoLayout; 482 } 483 484 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) { 485 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg=" 486 + (lp != null ? lp.packageName : null) 487 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null)); 488 if (lp != null && lp.windowAnimations != 0) { 489 // If this is a system resource, don't try to load it from the 490 // application resources. It is nice to avoid loading application 491 // resources if we can. 492 String packageName = lp.packageName != null ? lp.packageName : "android"; 493 int resId = lp.windowAnimations; 494 if ((resId&0xFF000000) == 0x01000000) { 495 packageName = "android"; 496 } 497 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package=" 498 + packageName); 499 return AttributeCache.instance().get(packageName, resId, 500 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId); 501 } 502 return null; 503 } 504 505 private AttributeCache.Entry getCachedAnimations(String packageName, int resId) { 506 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package=" 507 + packageName + " resId=0x" + Integer.toHexString(resId)); 508 if (packageName != null) { 509 if ((resId&0xFF000000) == 0x01000000) { 510 packageName = "android"; 511 } 512 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package=" 513 + packageName); 514 return AttributeCache.instance().get(packageName, resId, 515 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId); 516 } 517 return null; 518 } 519 520 Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) { 521 int anim = 0; 522 Context context = mContext; 523 if (animAttr >= 0) { 524 AttributeCache.Entry ent = getCachedAnimations(lp); 525 if (ent != null) { 526 context = ent.context; 527 anim = ent.array.getResourceId(animAttr, 0); 528 } 529 } 530 if (anim != 0) { 531 return AnimationUtils.loadAnimation(context, anim); 532 } 533 return null; 534 } 535 536 Animation loadAnimationRes(WindowManager.LayoutParams lp, int resId) { 537 Context context = mContext; 538 if (resId >= 0) { 539 AttributeCache.Entry ent = getCachedAnimations(lp); 540 if (ent != null) { 541 context = ent.context; 542 } 543 return AnimationUtils.loadAnimation(context, resId); 544 } 545 return null; 546 } 547 548 private Animation loadAnimationRes(String packageName, int resId) { 549 int anim = 0; 550 Context context = mContext; 551 if (resId >= 0) { 552 AttributeCache.Entry ent = getCachedAnimations(packageName, resId); 553 if (ent != null) { 554 context = ent.context; 555 anim = resId; 556 } 557 } 558 if (anim != 0) { 559 return AnimationUtils.loadAnimation(context, anim); 560 } 561 return null; 562 } 563 564 /** 565 * Compute the pivot point for an animation that is scaling from a small 566 * rect on screen to a larger rect. The pivot point varies depending on 567 * the distance between the inner and outer edges on both sides. This 568 * function computes the pivot point for one dimension. 569 * @param startPos Offset from left/top edge of outer rectangle to 570 * left/top edge of inner rectangle. 571 * @param finalScale The scaling factor between the size of the outer 572 * and inner rectangles. 573 */ 574 private static float computePivot(int startPos, float finalScale) { 575 576 /* 577 Theorem of intercepting lines: 578 579 + + +-----------------------------------------------+ 580 | | | | 581 | | | | 582 | | | | 583 | | | | 584 x | y | | | 585 | | | | 586 | | | | 587 | | | | 588 | | | | 589 | + | +--------------------+ | 590 | | | | | 591 | | | | | 592 | | | | | 593 | | | | | 594 | | | | | 595 | | | | | 596 | | | | | 597 | | | | | 598 | | | | | 599 | | | | | 600 | | | | | 601 | | | | | 602 | | | | | 603 | | | | | 604 | | | | | 605 | | | | | 606 | | | | | 607 | | +--------------------+ | 608 | | | 609 | | | 610 | | | 611 | | | 612 | | | 613 | | | 614 | | | 615 | +-----------------------------------------------+ 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 + ++ 626 p ++ 627 628 scale = (x - y) / x 629 <=> x = -y / (scale - 1) 630 */ 631 final float denom = finalScale-1; 632 if (Math.abs(denom) < .0001f) { 633 return startPos; 634 } 635 return -startPos / denom; 636 } 637 638 private Animation createScaleUpAnimationLocked(int transit, boolean enter, 639 Rect containingFrame) { 640 Animation a; 641 getDefaultNextAppTransitionStartRect(mTmpRect); 642 final int appWidth = containingFrame.width(); 643 final int appHeight = containingFrame.height(); 644 if (enter) { 645 // Entering app zooms out from the center of the initial rect. 646 float scaleW = mTmpRect.width() / (float) appWidth; 647 float scaleH = mTmpRect.height() / (float) appHeight; 648 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1, 649 computePivot(mTmpRect.left, scaleW), 650 computePivot(mTmpRect.top, scaleH)); 651 scale.setInterpolator(mDecelerateInterpolator); 652 653 Animation alpha = new AlphaAnimation(0, 1); 654 alpha.setInterpolator(mThumbnailFadeOutInterpolator); 655 656 AnimationSet set = new AnimationSet(false); 657 set.addAnimation(scale); 658 set.addAnimation(alpha); 659 set.setDetachWallpaper(true); 660 a = set; 661 } else if (transit == TRANSIT_WALLPAPER_INTRA_OPEN || 662 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) { 663 // If we are on top of the wallpaper, we need an animation that 664 // correctly handles the wallpaper staying static behind all of 665 // the animated elements. To do this, will just have the existing 666 // element fade out. 667 a = new AlphaAnimation(1, 0); 668 a.setDetachWallpaper(true); 669 } else { 670 // For normal animations, the exiting element just holds in place. 671 a = new AlphaAnimation(1, 1); 672 } 673 674 // Pick the desired duration. If this is an inter-activity transition, 675 // it is the standard duration for that. Otherwise we use the longer 676 // task transition duration. 677 final long duration; 678 switch (transit) { 679 case TRANSIT_ACTIVITY_OPEN: 680 case TRANSIT_ACTIVITY_CLOSE: 681 duration = mConfigShortAnimTime; 682 break; 683 default: 684 duration = DEFAULT_APP_TRANSITION_DURATION; 685 break; 686 } 687 a.setDuration(duration); 688 a.setFillAfter(true); 689 a.setInterpolator(mDecelerateInterpolator); 690 a.initialize(appWidth, appHeight, appWidth, appHeight); 691 return a; 692 } 693 694 private void getDefaultNextAppTransitionStartRect(Rect rect) { 695 if (mDefaultNextAppTransitionAnimationSpec == null || 696 mDefaultNextAppTransitionAnimationSpec.rect == null) { 697 Slog.e(TAG, "Starting rect for app requested, but none available", new Throwable()); 698 rect.setEmpty(); 699 } else { 700 rect.set(mDefaultNextAppTransitionAnimationSpec.rect); 701 } 702 } 703 704 void getNextAppTransitionStartRect(int taskId, Rect rect) { 705 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId); 706 if (spec == null) { 707 spec = mDefaultNextAppTransitionAnimationSpec; 708 } 709 if (spec == null || spec.rect == null) { 710 Slog.e(TAG, "Starting rect for task: " + taskId + " requested, but not available", 711 new Throwable()); 712 rect.setEmpty(); 713 } else { 714 rect.set(spec.rect); 715 } 716 } 717 718 private void putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height, 719 Bitmap bitmap) { 720 mDefaultNextAppTransitionAnimationSpec = new AppTransitionAnimationSpec(-1 /* taskId */, 721 bitmap, new Rect(left, top, left + width, top + height)); 722 } 723 724 /** 725 * @return the duration of the last clip reveal animation 726 */ 727 long getLastClipRevealTransitionDuration() { 728 return mLastClipRevealTransitionDuration; 729 } 730 731 /** 732 * @return the maximum distance the app surface is traveling of the last clip reveal animation 733 */ 734 int getLastClipRevealMaxTranslation() { 735 return mLastClipRevealMaxTranslation; 736 } 737 738 /** 739 * @return true if in the last app transition had a clip reveal animation, false otherwise 740 */ 741 boolean hadClipRevealAnimation() { 742 return mLastHadClipReveal; 743 } 744 745 /** 746 * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that 747 * the start rect is outside of the target rect, and there is a lot of movement going on. 748 * 749 * @param cutOff whether the start rect was not fully contained by the end rect 750 * @param translationX the total translation the surface moves in x direction 751 * @param translationY the total translation the surfaces moves in y direction 752 * @param displayFrame our display frame 753 * 754 * @return the duration of the clip reveal animation, in milliseconds 755 */ 756 private long calculateClipRevealTransitionDuration(boolean cutOff, float translationX, 757 float translationY, Rect displayFrame) { 758 if (!cutOff) { 759 return DEFAULT_APP_TRANSITION_DURATION; 760 } 761 final float fraction = Math.max(Math.abs(translationX) / displayFrame.width(), 762 Math.abs(translationY) / displayFrame.height()); 763 return (long) (DEFAULT_APP_TRANSITION_DURATION + fraction * 764 (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION)); 765 } 766 767 private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame, 768 Rect displayFrame) { 769 final Animation anim; 770 if (enter) { 771 final int appWidth = appFrame.width(); 772 final int appHeight = appFrame.height(); 773 774 // mTmpRect will contain an area around the launcher icon that was pressed. We will 775 // clip reveal from that area in the final area of the app. 776 getDefaultNextAppTransitionStartRect(mTmpRect); 777 778 float t = 0f; 779 if (appHeight > 0) { 780 t = (float) mTmpRect.top / displayFrame.height(); 781 } 782 int translationY = mClipRevealTranslationY + (int)(displayFrame.height() / 7f * t); 783 int translationX = 0; 784 int translationYCorrection = translationY; 785 int centerX = mTmpRect.centerX(); 786 int centerY = mTmpRect.centerY(); 787 int halfWidth = mTmpRect.width() / 2; 788 int halfHeight = mTmpRect.height() / 2; 789 int clipStartX = centerX - halfWidth - appFrame.left; 790 int clipStartY = centerY - halfHeight - appFrame.top; 791 boolean cutOff = false; 792 793 // If the starting rectangle is fully or partially outside of the target rectangle, we 794 // need to start the clipping at the edge and then achieve the rest with translation 795 // and extending the clip rect from that edge. 796 if (appFrame.top > centerY - halfHeight) { 797 translationY = (centerY - halfHeight) - appFrame.top; 798 translationYCorrection = 0; 799 clipStartY = 0; 800 cutOff = true; 801 } 802 if (appFrame.left > centerX - halfWidth) { 803 translationX = (centerX - halfWidth) - appFrame.left; 804 clipStartX = 0; 805 cutOff = true; 806 } 807 if (appFrame.right < centerX + halfWidth) { 808 translationX = (centerX + halfWidth) - appFrame.right; 809 clipStartX = appWidth - mTmpRect.width(); 810 cutOff = true; 811 } 812 final long duration = calculateClipRevealTransitionDuration(cutOff, translationX, 813 translationY, displayFrame); 814 815 // Clip third of the from size of launch icon, expand to full width/height 816 Animation clipAnimLR = new ClipRectLRAnimation( 817 clipStartX, clipStartX + mTmpRect.width(), 0, appWidth); 818 clipAnimLR.setInterpolator(mClipHorizontalInterpolator); 819 clipAnimLR.setDuration((long) (duration / 2.5f)); 820 821 TranslateAnimation translate = new TranslateAnimation(translationX, 0, translationY, 0); 822 translate.setInterpolator(cutOff ? TOUCH_RESPONSE_INTERPOLATOR 823 : mLinearOutSlowInInterpolator); 824 translate.setDuration(duration); 825 826 Animation clipAnimTB = new ClipRectTBAnimation( 827 clipStartY, clipStartY + mTmpRect.height(), 828 0, appHeight, 829 translationYCorrection, 0, 830 mLinearOutSlowInInterpolator); 831 clipAnimTB.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); 832 clipAnimTB.setDuration(duration); 833 834 // Quick fade-in from icon to app window 835 final long alphaDuration = duration / 4; 836 AlphaAnimation alpha = new AlphaAnimation(0.5f, 1); 837 alpha.setDuration(alphaDuration); 838 alpha.setInterpolator(mLinearOutSlowInInterpolator); 839 840 AnimationSet set = new AnimationSet(false); 841 set.addAnimation(clipAnimLR); 842 set.addAnimation(clipAnimTB); 843 set.addAnimation(translate); 844 set.addAnimation(alpha); 845 set.setZAdjustment(Animation.ZORDER_TOP); 846 set.initialize(appWidth, appHeight, appWidth, appHeight); 847 anim = set; 848 mLastHadClipReveal = true; 849 mLastClipRevealTransitionDuration = duration; 850 851 // If the start rect was full inside the target rect (cutOff == false), we don't need 852 // to store the translation, because it's only used if cutOff == true. 853 mLastClipRevealMaxTranslation = cutOff 854 ? Math.max(Math.abs(translationY), Math.abs(translationX)) : 0; 855 } else { 856 final long duration; 857 switch (transit) { 858 case TRANSIT_ACTIVITY_OPEN: 859 case TRANSIT_ACTIVITY_CLOSE: 860 duration = mConfigShortAnimTime; 861 break; 862 default: 863 duration = DEFAULT_APP_TRANSITION_DURATION; 864 break; 865 } 866 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN || 867 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) { 868 // If we are on top of the wallpaper, we need an animation that 869 // correctly handles the wallpaper staying static behind all of 870 // the animated elements. To do this, will just have the existing 871 // element fade out. 872 anim = new AlphaAnimation(1, 0); 873 anim.setDetachWallpaper(true); 874 } else { 875 // For normal animations, the exiting element just holds in place. 876 anim = new AlphaAnimation(1, 1); 877 } 878 anim.setInterpolator(mDecelerateInterpolator); 879 anim.setDuration(duration); 880 anim.setFillAfter(true); 881 } 882 return anim; 883 } 884 885 /** 886 * Prepares the specified animation with a standard duration, interpolator, etc. 887 */ 888 Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight, 889 long duration, Interpolator interpolator) { 890 if (duration > 0) { 891 a.setDuration(duration); 892 } 893 a.setFillAfter(true); 894 if (interpolator != null) { 895 a.setInterpolator(interpolator); 896 } 897 a.initialize(appWidth, appHeight, appWidth, appHeight); 898 return a; 899 } 900 901 /** 902 * Prepares the specified animation with a standard duration, interpolator, etc. 903 */ 904 Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) { 905 // Pick the desired duration. If this is an inter-activity transition, 906 // it is the standard duration for that. Otherwise we use the longer 907 // task transition duration. 908 final int duration; 909 switch (transit) { 910 case TRANSIT_ACTIVITY_OPEN: 911 case TRANSIT_ACTIVITY_CLOSE: 912 duration = mConfigShortAnimTime; 913 break; 914 default: 915 duration = DEFAULT_APP_TRANSITION_DURATION; 916 break; 917 } 918 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration, 919 mDecelerateInterpolator); 920 } 921 922 /** 923 * Return the current thumbnail transition state. 924 */ 925 int getThumbnailTransitionState(boolean enter) { 926 if (enter) { 927 if (mNextAppTransitionScaleUp) { 928 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP; 929 } else { 930 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN; 931 } 932 } else { 933 if (mNextAppTransitionScaleUp) { 934 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP; 935 } else { 936 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN; 937 } 938 } 939 } 940 941 /** 942 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity 943 * when a thumbnail is specified with the pending animation override. 944 */ 945 Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets, 946 Bitmap thumbnailHeader, final int taskId, int uiMode, int orientation) { 947 Animation a; 948 final int thumbWidthI = thumbnailHeader.getWidth(); 949 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 950 final int thumbHeightI = thumbnailHeader.getHeight(); 951 final int appWidth = appRect.width(); 952 953 float scaleW = appWidth / thumbWidth; 954 getNextAppTransitionStartRect(taskId, mTmpRect); 955 final float fromX; 956 float fromY; 957 final float toX; 958 float toY; 959 final float pivotX; 960 final float pivotY; 961 if (shouldScaleDownThumbnailTransition(uiMode, orientation)) { 962 fromX = mTmpRect.left; 963 fromY = mTmpRect.top; 964 965 // For the curved translate animation to work, the pivot points needs to be at the 966 // same absolute position as the one from the real surface. 967 toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left; 968 toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top; 969 pivotX = mTmpRect.width() / 2; 970 pivotY = appRect.height() / 2 / scaleW; 971 if (mGridLayoutRecentsEnabled) { 972 // In the grid layout, the header is displayed above the thumbnail instead of 973 // overlapping it. 974 fromY -= thumbHeightI; 975 toY -= thumbHeightI * scaleW; 976 } 977 } else { 978 pivotX = 0; 979 pivotY = 0; 980 fromX = mTmpRect.left; 981 fromY = mTmpRect.top; 982 toX = appRect.left; 983 toY = appRect.top; 984 } 985 final long duration = getAspectScaleDuration(); 986 final Interpolator interpolator = getAspectScaleInterpolator(); 987 if (mNextAppTransitionScaleUp) { 988 // Animation up from the thumbnail to the full screen 989 Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY); 990 scale.setInterpolator(interpolator); 991 scale.setDuration(duration); 992 Animation alpha = new AlphaAnimation(1f, 0f); 993 alpha.setInterpolator(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS 994 ? THUMBNAIL_DOCK_INTERPOLATOR : mThumbnailFadeOutInterpolator); 995 alpha.setDuration(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS 996 ? duration / 2 997 : duration); 998 Animation translate = createCurvedMotion(fromX, toX, fromY, toY); 999 translate.setInterpolator(interpolator); 1000 translate.setDuration(duration); 1001 1002 mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI); 1003 mTmpToClipRect.set(appRect); 1004 1005 // Containing frame is in screen space, but we need the clip rect in the 1006 // app space. 1007 mTmpToClipRect.offsetTo(0, 0); 1008 mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW); 1009 mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW); 1010 1011 if (contentInsets != null) { 1012 mTmpToClipRect.inset((int) (-contentInsets.left * scaleW), 1013 (int) (-contentInsets.top * scaleW), 1014 (int) (-contentInsets.right * scaleW), 1015 (int) (-contentInsets.bottom * scaleW)); 1016 } 1017 1018 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect); 1019 clipAnim.setInterpolator(interpolator); 1020 clipAnim.setDuration(duration); 1021 1022 // This AnimationSet uses the Interpolators assigned above. 1023 AnimationSet set = new AnimationSet(false); 1024 set.addAnimation(scale); 1025 if (!mGridLayoutRecentsEnabled) { 1026 // In the grid layout, the header should be shown for the whole animation. 1027 set.addAnimation(alpha); 1028 } 1029 set.addAnimation(translate); 1030 set.addAnimation(clipAnim); 1031 a = set; 1032 } else { 1033 // Animation down from the full screen to the thumbnail 1034 Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY); 1035 scale.setInterpolator(interpolator); 1036 scale.setDuration(duration); 1037 Animation alpha = new AlphaAnimation(0f, 1f); 1038 alpha.setInterpolator(mThumbnailFadeInInterpolator); 1039 alpha.setDuration(duration); 1040 Animation translate = createCurvedMotion(toX, fromX, toY, fromY); 1041 translate.setInterpolator(interpolator); 1042 translate.setDuration(duration); 1043 1044 // This AnimationSet uses the Interpolators assigned above. 1045 AnimationSet set = new AnimationSet(false); 1046 set.addAnimation(scale); 1047 if (!mGridLayoutRecentsEnabled) { 1048 // In the grid layout, the header should be shown for the whole animation. 1049 set.addAnimation(alpha); 1050 } 1051 set.addAnimation(translate); 1052 a = set; 1053 1054 } 1055 return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0, 1056 null); 1057 } 1058 1059 private Animation createCurvedMotion(float fromX, float toX, float fromY, float toY) { 1060 1061 // Almost no x-change - use linear animation 1062 if (Math.abs(toX - fromX) < 1f || mNextAppTransition != TRANSIT_DOCK_TASK_FROM_RECENTS) { 1063 return new TranslateAnimation(fromX, toX, fromY, toY); 1064 } else { 1065 final Path path = createCurvedPath(fromX, toX, fromY, toY); 1066 return new CurvedTranslateAnimation(path); 1067 } 1068 } 1069 1070 private Path createCurvedPath(float fromX, float toX, float fromY, float toY) { 1071 final Path path = new Path(); 1072 path.moveTo(fromX, fromY); 1073 1074 if (fromY > toY) { 1075 // If the object needs to go up, move it in horizontal direction first, then vertical. 1076 path.cubicTo(fromX, fromY, toX, 0.9f * fromY + 0.1f * toY, toX, toY); 1077 } else { 1078 // If the object needs to go down, move it in vertical direction first, then horizontal. 1079 path.cubicTo(fromX, fromY, fromX, 0.1f * fromY + 0.9f * toY, toX, toY); 1080 } 1081 return path; 1082 } 1083 1084 private long getAspectScaleDuration() { 1085 if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) { 1086 return (long) (THUMBNAIL_APP_TRANSITION_DURATION * 1.35f); 1087 } else { 1088 return THUMBNAIL_APP_TRANSITION_DURATION; 1089 } 1090 } 1091 1092 private Interpolator getAspectScaleInterpolator() { 1093 if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) { 1094 return mFastOutSlowInInterpolator; 1095 } else { 1096 return TOUCH_RESPONSE_INTERPOLATOR; 1097 } 1098 } 1099 1100 /** 1101 * This alternate animation is created when we are doing a thumbnail transition, for the 1102 * activity that is leaving, and the activity that is entering. 1103 */ 1104 Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState, 1105 int uiMode, int orientation, int transit, Rect containingFrame, Rect contentInsets, 1106 @Nullable Rect surfaceInsets, boolean freeform, int taskId) { 1107 Animation a; 1108 final int appWidth = containingFrame.width(); 1109 final int appHeight = containingFrame.height(); 1110 getDefaultNextAppTransitionStartRect(mTmpRect); 1111 final int thumbWidthI = mTmpRect.width(); 1112 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 1113 final int thumbHeightI = mTmpRect.height(); 1114 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 1115 final int thumbStartX = mTmpRect.left - containingFrame.left - contentInsets.left; 1116 final int thumbStartY = mTmpRect.top - containingFrame.top; 1117 1118 switch (thumbTransitState) { 1119 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: 1120 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: { 1121 final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP; 1122 if (freeform && scaleUp) { 1123 a = createAspectScaledThumbnailEnterFreeformAnimationLocked( 1124 containingFrame, surfaceInsets, taskId); 1125 } else if (freeform) { 1126 a = createAspectScaledThumbnailExitFreeformAnimationLocked( 1127 containingFrame, surfaceInsets, taskId); 1128 } else { 1129 AnimationSet set = new AnimationSet(true); 1130 1131 // In portrait, we scale to fit the width 1132 mTmpFromClipRect.set(containingFrame); 1133 mTmpToClipRect.set(containingFrame); 1134 1135 // Containing frame is in screen space, but we need the clip rect in the 1136 // app space. 1137 mTmpFromClipRect.offsetTo(0, 0); 1138 mTmpToClipRect.offsetTo(0, 0); 1139 1140 // Exclude insets region from the source clip. 1141 mTmpFromClipRect.inset(contentInsets); 1142 mNextAppTransitionInsets.set(contentInsets); 1143 1144 if (shouldScaleDownThumbnailTransition(uiMode, orientation)) { 1145 // We scale the width and clip to the top/left square 1146 float scale = thumbWidth / 1147 (appWidth - contentInsets.left - contentInsets.right); 1148 if (!mGridLayoutRecentsEnabled) { 1149 int unscaledThumbHeight = (int) (thumbHeight / scale); 1150 mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight; 1151 } 1152 1153 mNextAppTransitionInsets.set(contentInsets); 1154 1155 Animation scaleAnim = new ScaleAnimation( 1156 scaleUp ? scale : 1, scaleUp ? 1 : scale, 1157 scaleUp ? scale : 1, scaleUp ? 1 : scale, 1158 containingFrame.width() / 2f, 1159 containingFrame.height() / 2f + contentInsets.top); 1160 final float targetX = (mTmpRect.left - containingFrame.left); 1161 final float x = containingFrame.width() / 2f 1162 - containingFrame.width() / 2f * scale; 1163 final float targetY = (mTmpRect.top - containingFrame.top); 1164 final float y = containingFrame.height() / 2f 1165 - containingFrame.height() / 2f * scale; 1166 final float startX = targetX - x; 1167 final float startY = targetY - y; 1168 Animation clipAnim = scaleUp 1169 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect) 1170 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect); 1171 Animation translateAnim = scaleUp 1172 ? createCurvedMotion(startX, 0, startY - contentInsets.top, 0) 1173 : createCurvedMotion(0, startX, 0, startY - contentInsets.top); 1174 1175 set.addAnimation(clipAnim); 1176 set.addAnimation(scaleAnim); 1177 set.addAnimation(translateAnim); 1178 1179 } else { 1180 // In landscape, we don't scale at all and only crop 1181 mTmpFromClipRect.bottom = mTmpFromClipRect.top + thumbHeightI; 1182 mTmpFromClipRect.right = mTmpFromClipRect.left + thumbWidthI; 1183 1184 Animation clipAnim = scaleUp 1185 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect) 1186 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect); 1187 Animation translateAnim = scaleUp 1188 ? createCurvedMotion(thumbStartX, 0, 1189 thumbStartY - contentInsets.top, 0) 1190 : createCurvedMotion(0, thumbStartX, 0, 1191 thumbStartY - contentInsets.top); 1192 1193 set.addAnimation(clipAnim); 1194 set.addAnimation(translateAnim); 1195 } 1196 a = set; 1197 a.setZAdjustment(Animation.ZORDER_TOP); 1198 } 1199 break; 1200 } 1201 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: { 1202 // Previous app window during the scale up 1203 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 1204 // Fade out the source activity if we are animating to a wallpaper 1205 // activity. 1206 a = new AlphaAnimation(1, 0); 1207 } else { 1208 a = new AlphaAnimation(1, 1); 1209 } 1210 break; 1211 } 1212 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: { 1213 // Target app window during the scale down 1214 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 1215 // Fade in the destination activity if we are animating from a wallpaper 1216 // activity. 1217 a = new AlphaAnimation(0, 1); 1218 } else { 1219 a = new AlphaAnimation(1, 1); 1220 } 1221 break; 1222 } 1223 default: 1224 throw new RuntimeException("Invalid thumbnail transition state"); 1225 } 1226 1227 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, 1228 getAspectScaleDuration(), getAspectScaleInterpolator()); 1229 } 1230 1231 private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame, 1232 @Nullable Rect surfaceInsets, int taskId) { 1233 getNextAppTransitionStartRect(taskId, mTmpRect); 1234 return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets, 1235 true); 1236 } 1237 1238 private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame, 1239 @Nullable Rect surfaceInsets, int taskId) { 1240 getNextAppTransitionStartRect(taskId, mTmpRect); 1241 return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets, 1242 false); 1243 } 1244 1245 private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame, 1246 Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) { 1247 final float sourceWidth = sourceFrame.width(); 1248 final float sourceHeight = sourceFrame.height(); 1249 final float destWidth = destFrame.width(); 1250 final float destHeight = destFrame.height(); 1251 final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth; 1252 final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight; 1253 AnimationSet set = new AnimationSet(true); 1254 final int surfaceInsetsH = surfaceInsets == null 1255 ? 0 : surfaceInsets.left + surfaceInsets.right; 1256 final int surfaceInsetsV = surfaceInsets == null 1257 ? 0 : surfaceInsets.top + surfaceInsets.bottom; 1258 // We want the scaling to happen from the center of the surface. In order to achieve that, 1259 // we need to account for surface insets that will be used to enlarge the surface. 1260 final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2; 1261 final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2; 1262 final ScaleAnimation scale = enter ? 1263 new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter) 1264 : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter); 1265 final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2; 1266 final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2; 1267 final int destHCenter = destFrame.left + destFrame.width() / 2; 1268 final int destVCenter = destFrame.top + destFrame.height() / 2; 1269 final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter; 1270 final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter; 1271 final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0) 1272 : new TranslateAnimation(0, fromX, 0, fromY); 1273 set.addAnimation(scale); 1274 set.addAnimation(translation); 1275 1276 final IRemoteCallback callback = mAnimationFinishedCallback; 1277 if (callback != null) { 1278 set.setAnimationListener(new Animation.AnimationListener() { 1279 @Override 1280 public void onAnimationStart(Animation animation) { } 1281 1282 @Override 1283 public void onAnimationEnd(Animation animation) { 1284 mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK, callback).sendToTarget(); 1285 } 1286 1287 @Override 1288 public void onAnimationRepeat(Animation animation) { } 1289 }); 1290 } 1291 return set; 1292 } 1293 1294 /** 1295 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity 1296 * when a thumbnail is specified with the pending animation override. 1297 */ 1298 Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit, 1299 Bitmap thumbnailHeader) { 1300 Animation a; 1301 getDefaultNextAppTransitionStartRect(mTmpRect); 1302 final int thumbWidthI = thumbnailHeader.getWidth(); 1303 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 1304 final int thumbHeightI = thumbnailHeader.getHeight(); 1305 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 1306 1307 if (mNextAppTransitionScaleUp) { 1308 // Animation for the thumbnail zooming from its initial size to the full screen 1309 float scaleW = appWidth / thumbWidth; 1310 float scaleH = appHeight / thumbHeight; 1311 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 1312 computePivot(mTmpRect.left, 1 / scaleW), 1313 computePivot(mTmpRect.top, 1 / scaleH)); 1314 scale.setInterpolator(mDecelerateInterpolator); 1315 1316 Animation alpha = new AlphaAnimation(1, 0); 1317 alpha.setInterpolator(mThumbnailFadeOutInterpolator); 1318 1319 // This AnimationSet uses the Interpolators assigned above. 1320 AnimationSet set = new AnimationSet(false); 1321 set.addAnimation(scale); 1322 set.addAnimation(alpha); 1323 a = set; 1324 } else { 1325 // Animation for the thumbnail zooming down from the full screen to its final size 1326 float scaleW = appWidth / thumbWidth; 1327 float scaleH = appHeight / thumbHeight; 1328 a = new ScaleAnimation(scaleW, 1, scaleH, 1, 1329 computePivot(mTmpRect.left, 1 / scaleW), 1330 computePivot(mTmpRect.top, 1 / scaleH)); 1331 } 1332 1333 return prepareThumbnailAnimation(a, appWidth, appHeight, transit); 1334 } 1335 1336 /** 1337 * This animation is created when we are doing a thumbnail transition, for the activity that is 1338 * leaving, and the activity that is entering. 1339 */ 1340 Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame, 1341 int transit, int taskId) { 1342 final int appWidth = containingFrame.width(); 1343 final int appHeight = containingFrame.height(); 1344 Bitmap thumbnailHeader = getAppTransitionThumbnailHeader(taskId); 1345 Animation a; 1346 getDefaultNextAppTransitionStartRect(mTmpRect); 1347 final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth; 1348 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 1349 final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight; 1350 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 1351 1352 switch (thumbTransitState) { 1353 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: { 1354 // Entering app scales up with the thumbnail 1355 float scaleW = thumbWidth / appWidth; 1356 float scaleH = thumbHeight / appHeight; 1357 a = new ScaleAnimation(scaleW, 1, scaleH, 1, 1358 computePivot(mTmpRect.left, scaleW), 1359 computePivot(mTmpRect.top, scaleH)); 1360 break; 1361 } 1362 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: { 1363 // Exiting app while the thumbnail is scaling up should fade or stay in place 1364 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 1365 // Fade out while bringing up selected activity. This keeps the 1366 // current activity from showing through a launching wallpaper 1367 // activity. 1368 a = new AlphaAnimation(1, 0); 1369 } else { 1370 // noop animation 1371 a = new AlphaAnimation(1, 1); 1372 } 1373 break; 1374 } 1375 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: { 1376 // Entering the other app, it should just be visible while we scale the thumbnail 1377 // down above it 1378 a = new AlphaAnimation(1, 1); 1379 break; 1380 } 1381 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: { 1382 // Exiting the current app, the app should scale down with the thumbnail 1383 float scaleW = thumbWidth / appWidth; 1384 float scaleH = thumbHeight / appHeight; 1385 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 1386 computePivot(mTmpRect.left, scaleW), 1387 computePivot(mTmpRect.top, scaleH)); 1388 1389 Animation alpha = new AlphaAnimation(1, 0); 1390 1391 AnimationSet set = new AnimationSet(true); 1392 set.addAnimation(scale); 1393 set.addAnimation(alpha); 1394 set.setZAdjustment(Animation.ZORDER_TOP); 1395 a = set; 1396 break; 1397 } 1398 default: 1399 throw new RuntimeException("Invalid thumbnail transition state"); 1400 } 1401 1402 return prepareThumbnailAnimation(a, appWidth, appHeight, transit); 1403 } 1404 1405 private Animation createRelaunchAnimation(Rect containingFrame, Rect contentInsets) { 1406 getDefaultNextAppTransitionStartRect(mTmpFromClipRect); 1407 final int left = mTmpFromClipRect.left; 1408 final int top = mTmpFromClipRect.top; 1409 mTmpFromClipRect.offset(-left, -top); 1410 // TODO: Isn't that strange that we ignore exact position of the containingFrame? 1411 mTmpToClipRect.set(0, 0, containingFrame.width(), containingFrame.height()); 1412 AnimationSet set = new AnimationSet(true); 1413 float fromWidth = mTmpFromClipRect.width(); 1414 float toWidth = mTmpToClipRect.width(); 1415 float fromHeight = mTmpFromClipRect.height(); 1416 // While the window might span the whole display, the actual content will be cropped to the 1417 // system decoration frame, for example when the window is docked. We need to take into 1418 // account the visible height when constructing the animation. 1419 float toHeight = mTmpToClipRect.height() - contentInsets.top - contentInsets.bottom; 1420 int translateAdjustment = 0; 1421 if (fromWidth <= toWidth && fromHeight <= toHeight) { 1422 // The final window is larger in both dimensions than current window (e.g. we are 1423 // maximizing), so we can simply unclip the new window and there will be no disappearing 1424 // frame. 1425 set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)); 1426 } else { 1427 // The disappearing window has one larger dimension. We need to apply scaling, so the 1428 // first frame of the entry animation matches the old window. 1429 set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1)); 1430 // We might not be going exactly full screen, but instead be aligned under the status 1431 // bar using cropping. We still need to account for the cropped part, which will also 1432 // be scaled. 1433 translateAdjustment = (int) (contentInsets.top * fromHeight / toHeight); 1434 } 1435 1436 // We animate the translation from the old position of the removed window, to the new 1437 // position of the added window. The latter might not be full screen, for example docked for 1438 // docked windows. 1439 TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left, 1440 0, top - containingFrame.top - translateAdjustment, 0); 1441 set.addAnimation(translate); 1442 set.setDuration(DEFAULT_APP_TRANSITION_DURATION); 1443 set.setZAdjustment(Animation.ZORDER_TOP); 1444 return set; 1445 } 1446 1447 /** 1448 * @return true if and only if the first frame of the transition can be skipped, i.e. the first 1449 * frame of the transition doesn't change the visuals on screen, so we can start 1450 * directly with the second one 1451 */ 1452 boolean canSkipFirstFrame() { 1453 return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM 1454 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE 1455 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL 1456 && mNextAppTransition != TRANSIT_KEYGUARD_GOING_AWAY; 1457 } 1458 1459 /** 1460 * 1461 * @param frame These are the bounds of the window when it finishes the animation. This is where 1462 * the animation must usually finish in entrance animation, as the next frame will 1463 * display the window at these coordinates. In case of exit animation, this is 1464 * where the animation must start, as the frame before the animation is displaying 1465 * the window at these bounds. 1466 * @param insets Knowing where the window will be positioned is not enough. Some parts of the 1467 * window might be obscured, usually by the system windows (status bar and 1468 * navigation bar) and we use content insets to convey that information. This 1469 * usually affects the animation aspects vertically, as the system decoration is 1470 * at the top and the bottom. For example when we animate from full screen to 1471 * recents, we want to exclude the covered parts, because they won't match the 1472 * thumbnail after the last frame is executed. 1473 * @param surfaceInsets In rare situation the surface is larger than the content and we need to 1474 * know about this to make the animation frames match. We currently use 1475 * this for freeform windows, which have larger surfaces to display 1476 * shadows. When we animate them from recents, we want to match the content 1477 * to the recents thumbnail and hence need to account for the surface being 1478 * bigger. 1479 */ 1480 Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int uiMode, 1481 int orientation, Rect frame, Rect displayFrame, Rect insets, 1482 @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform, 1483 int taskId) { 1484 Animation a; 1485 if (isKeyguardGoingAwayTransit(transit) && enter) { 1486 a = loadKeyguardExitAnimation(transit); 1487 } else if (transit == TRANSIT_KEYGUARD_OCCLUDE) { 1488 a = null; 1489 } else if (transit == TRANSIT_KEYGUARD_UNOCCLUDE && !enter) { 1490 a = loadAnimationRes(lp, com.android.internal.R.anim.wallpaper_open_exit); 1491 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN 1492 || transit == TRANSIT_TASK_OPEN 1493 || transit == TRANSIT_TASK_TO_FRONT)) { 1494 a = loadAnimationRes(lp, enter 1495 ? com.android.internal.R.anim.voice_activity_open_enter 1496 : com.android.internal.R.anim.voice_activity_open_exit); 1497 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1498 "applyAnimation voice:" 1499 + " anim=" + a + " transit=" + appTransitionToString(transit) 1500 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); 1501 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE 1502 || transit == TRANSIT_TASK_CLOSE 1503 || transit == TRANSIT_TASK_TO_BACK)) { 1504 a = loadAnimationRes(lp, enter 1505 ? com.android.internal.R.anim.voice_activity_close_enter 1506 : com.android.internal.R.anim.voice_activity_close_exit); 1507 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1508 "applyAnimation voice:" 1509 + " anim=" + a + " transit=" + appTransitionToString(transit) 1510 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); 1511 } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) { 1512 a = createRelaunchAnimation(frame, insets); 1513 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1514 "applyAnimation:" 1515 + " anim=" + a + " nextAppTransition=" + mNextAppTransition 1516 + " transit=" + appTransitionToString(transit) 1517 + " Callers=" + Debug.getCallers(3)); 1518 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { 1519 a = loadAnimationRes(mNextAppTransitionPackage, enter ? 1520 mNextAppTransitionEnter : mNextAppTransitionExit); 1521 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1522 "applyAnimation:" 1523 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM" 1524 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1525 + " Callers=" + Debug.getCallers(3)); 1526 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) { 1527 a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace); 1528 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1529 "applyAnimation:" 1530 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE" 1531 + " transit=" + appTransitionToString(transit) 1532 + " Callers=" + Debug.getCallers(3)); 1533 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) { 1534 a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame); 1535 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1536 "applyAnimation:" 1537 + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL" 1538 + " transit=" + appTransitionToString(transit) 1539 + " Callers=" + Debug.getCallers(3)); 1540 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) { 1541 a = createScaleUpAnimationLocked(transit, enter, frame); 1542 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1543 "applyAnimation:" 1544 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP" 1545 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1546 + " Callers=" + Debug.getCallers(3)); 1547 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP || 1548 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) { 1549 mNextAppTransitionScaleUp = 1550 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP); 1551 a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter), 1552 frame, transit, taskId); 1553 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 1554 String animName = mNextAppTransitionScaleUp ? 1555 "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN"; 1556 Slog.v(TAG, "applyAnimation:" 1557 + " anim=" + a + " nextAppTransition=" + animName 1558 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1559 + " Callers=" + Debug.getCallers(3)); 1560 } 1561 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP || 1562 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) { 1563 mNextAppTransitionScaleUp = 1564 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP); 1565 a = createAspectScaledThumbnailEnterExitAnimationLocked( 1566 getThumbnailTransitionState(enter), uiMode, orientation, transit, frame, 1567 insets, surfaceInsets, freeform, taskId); 1568 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 1569 String animName = mNextAppTransitionScaleUp ? 1570 "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN"; 1571 Slog.v(TAG, "applyAnimation:" 1572 + " anim=" + a + " nextAppTransition=" + animName 1573 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1574 + " Callers=" + Debug.getCallers(3)); 1575 } 1576 } else { 1577 int animAttr = 0; 1578 switch (transit) { 1579 case TRANSIT_ACTIVITY_OPEN: 1580 animAttr = enter 1581 ? WindowAnimation_activityOpenEnterAnimation 1582 : WindowAnimation_activityOpenExitAnimation; 1583 break; 1584 case TRANSIT_ACTIVITY_CLOSE: 1585 animAttr = enter 1586 ? WindowAnimation_activityCloseEnterAnimation 1587 : WindowAnimation_activityCloseExitAnimation; 1588 break; 1589 case TRANSIT_DOCK_TASK_FROM_RECENTS: 1590 case TRANSIT_TASK_OPEN: 1591 animAttr = enter 1592 ? WindowAnimation_taskOpenEnterAnimation 1593 : WindowAnimation_taskOpenExitAnimation; 1594 break; 1595 case TRANSIT_TASK_CLOSE: 1596 animAttr = enter 1597 ? WindowAnimation_taskCloseEnterAnimation 1598 : WindowAnimation_taskCloseExitAnimation; 1599 break; 1600 case TRANSIT_TASK_TO_FRONT: 1601 animAttr = enter 1602 ? WindowAnimation_taskToFrontEnterAnimation 1603 : WindowAnimation_taskToFrontExitAnimation; 1604 break; 1605 case TRANSIT_TASK_TO_BACK: 1606 animAttr = enter 1607 ? WindowAnimation_taskToBackEnterAnimation 1608 : WindowAnimation_taskToBackExitAnimation; 1609 break; 1610 case TRANSIT_WALLPAPER_OPEN: 1611 animAttr = enter 1612 ? WindowAnimation_wallpaperOpenEnterAnimation 1613 : WindowAnimation_wallpaperOpenExitAnimation; 1614 break; 1615 case TRANSIT_WALLPAPER_CLOSE: 1616 animAttr = enter 1617 ? WindowAnimation_wallpaperCloseEnterAnimation 1618 : WindowAnimation_wallpaperCloseExitAnimation; 1619 break; 1620 case TRANSIT_WALLPAPER_INTRA_OPEN: 1621 animAttr = enter 1622 ? WindowAnimation_wallpaperIntraOpenEnterAnimation 1623 : WindowAnimation_wallpaperIntraOpenExitAnimation; 1624 break; 1625 case TRANSIT_WALLPAPER_INTRA_CLOSE: 1626 animAttr = enter 1627 ? WindowAnimation_wallpaperIntraCloseEnterAnimation 1628 : WindowAnimation_wallpaperIntraCloseExitAnimation; 1629 break; 1630 case TRANSIT_TASK_OPEN_BEHIND: 1631 animAttr = enter 1632 ? WindowAnimation_launchTaskBehindSourceAnimation 1633 : WindowAnimation_launchTaskBehindTargetAnimation; 1634 } 1635 a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null; 1636 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1637 "applyAnimation:" 1638 + " anim=" + a 1639 + " animAttr=0x" + Integer.toHexString(animAttr) 1640 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1641 + " Callers=" + Debug.getCallers(3)); 1642 } 1643 return a; 1644 } 1645 1646 private Animation loadKeyguardExitAnimation(int transit) { 1647 if ((mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) != 0) { 1648 return null; 1649 } 1650 final boolean toShade = 1651 (mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0; 1652 return mService.mPolicy.createHiddenByKeyguardExit( 1653 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER, toShade); 1654 } 1655 1656 int getAppStackClipMode() { 1657 // When dismiss keyguard animation occurs, clip before the animation to prevent docked 1658 // app from showing beyond the divider 1659 if (mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY 1660 || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) { 1661 return STACK_CLIP_BEFORE_ANIM; 1662 } 1663 return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH 1664 || mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS 1665 || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL 1666 ? STACK_CLIP_NONE 1667 : STACK_CLIP_AFTER_ANIM; 1668 } 1669 1670 public int getTransitFlags() { 1671 return mNextAppTransitionFlags; 1672 } 1673 1674 void postAnimationCallback() { 1675 if (mNextAppTransitionCallback != null) { 1676 mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK, 1677 mNextAppTransitionCallback)); 1678 mNextAppTransitionCallback = null; 1679 } 1680 } 1681 1682 void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, 1683 IRemoteCallback startedCallback) { 1684 if (isTransitionSet()) { 1685 clear(); 1686 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM; 1687 mNextAppTransitionPackage = packageName; 1688 mNextAppTransitionEnter = enterAnim; 1689 mNextAppTransitionExit = exitAnim; 1690 postAnimationCallback(); 1691 mNextAppTransitionCallback = startedCallback; 1692 } else { 1693 postAnimationCallback(); 1694 } 1695 } 1696 1697 void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, 1698 int startHeight) { 1699 if (isTransitionSet()) { 1700 clear(); 1701 mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP; 1702 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null); 1703 postAnimationCallback(); 1704 } 1705 } 1706 1707 void overridePendingAppTransitionClipReveal(int startX, int startY, 1708 int startWidth, int startHeight) { 1709 if (isTransitionSet()) { 1710 clear(); 1711 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL; 1712 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null); 1713 postAnimationCallback(); 1714 } 1715 } 1716 1717 void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY, 1718 IRemoteCallback startedCallback, boolean scaleUp) { 1719 if (isTransitionSet()) { 1720 clear(); 1721 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP 1722 : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN; 1723 mNextAppTransitionScaleUp = scaleUp; 1724 putDefaultNextAppTransitionCoordinates(startX, startY, 0, 0, srcThumb); 1725 postAnimationCallback(); 1726 mNextAppTransitionCallback = startedCallback; 1727 } else { 1728 postAnimationCallback(); 1729 } 1730 } 1731 1732 void overridePendingAppTransitionAspectScaledThumb(Bitmap srcThumb, int startX, int startY, 1733 int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) { 1734 if (isTransitionSet()) { 1735 clear(); 1736 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP 1737 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 1738 mNextAppTransitionScaleUp = scaleUp; 1739 putDefaultNextAppTransitionCoordinates(startX, startY, targetWidth, targetHeight, 1740 srcThumb); 1741 postAnimationCallback(); 1742 mNextAppTransitionCallback = startedCallback; 1743 } else { 1744 postAnimationCallback(); 1745 } 1746 } 1747 1748 public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs, 1749 IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback, 1750 boolean scaleUp) { 1751 if (isTransitionSet()) { 1752 clear(); 1753 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP 1754 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 1755 mNextAppTransitionScaleUp = scaleUp; 1756 if (specs != null) { 1757 for (int i = 0; i < specs.length; i++) { 1758 AppTransitionAnimationSpec spec = specs[i]; 1759 if (spec != null) { 1760 mNextAppTransitionAnimationsSpecs.put(spec.taskId, spec); 1761 if (i == 0) { 1762 // In full screen mode, the transition code depends on the default spec 1763 // to be set. 1764 Rect rect = spec.rect; 1765 putDefaultNextAppTransitionCoordinates(rect.left, rect.top, 1766 rect.width(), rect.height(), spec.bitmap); 1767 } 1768 } 1769 } 1770 } 1771 postAnimationCallback(); 1772 mNextAppTransitionCallback = onAnimationStartedCallback; 1773 mAnimationFinishedCallback = onAnimationFinishedCallback; 1774 } else { 1775 postAnimationCallback(); 1776 } 1777 } 1778 1779 void overridePendingAppTransitionMultiThumbFuture( 1780 IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback, 1781 boolean scaleUp) { 1782 if (isTransitionSet()) { 1783 clear(); 1784 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP 1785 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 1786 mNextAppTransitionAnimationsSpecsFuture = specsFuture; 1787 mNextAppTransitionScaleUp = scaleUp; 1788 mNextAppTransitionFutureCallback = callback; 1789 } 1790 } 1791 1792 void overrideInPlaceAppTransition(String packageName, int anim) { 1793 if (isTransitionSet()) { 1794 clear(); 1795 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE; 1796 mNextAppTransitionPackage = packageName; 1797 mNextAppTransitionInPlace = anim; 1798 } else { 1799 postAnimationCallback(); 1800 } 1801 } 1802 1803 /** 1804 * If a future is set for the app transition specs, fetch it in another thread. 1805 */ 1806 private void fetchAppTransitionSpecsFromFuture() { 1807 if (mNextAppTransitionAnimationsSpecsFuture != null) { 1808 mNextAppTransitionAnimationsSpecsPending = true; 1809 final IAppTransitionAnimationSpecsFuture future 1810 = mNextAppTransitionAnimationsSpecsFuture; 1811 mNextAppTransitionAnimationsSpecsFuture = null; 1812 mDefaultExecutor.execute(() -> { 1813 AppTransitionAnimationSpec[] specs = null; 1814 try { 1815 Binder.allowBlocking(future.asBinder()); 1816 specs = future.get(); 1817 } catch (RemoteException e) { 1818 Slog.w(TAG, "Failed to fetch app transition specs: " + e); 1819 } 1820 synchronized (mService.mWindowMap) { 1821 mNextAppTransitionAnimationsSpecsPending = false; 1822 overridePendingAppTransitionMultiThumb(specs, 1823 mNextAppTransitionFutureCallback, null /* finishedCallback */, 1824 mNextAppTransitionScaleUp); 1825 mNextAppTransitionFutureCallback = null; 1826 if (specs != null) { 1827 mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp); 1828 } 1829 } 1830 mService.requestTraversal(); 1831 }); 1832 } 1833 } 1834 1835 @Override 1836 public String toString() { 1837 return "mNextAppTransition=" + appTransitionToString(mNextAppTransition); 1838 } 1839 1840 /** 1841 * Returns the human readable name of a window transition. 1842 * 1843 * @param transition The window transition. 1844 * @return The transition symbolic name. 1845 */ 1846 public static String appTransitionToString(int transition) { 1847 switch (transition) { 1848 case TRANSIT_UNSET: { 1849 return "TRANSIT_UNSET"; 1850 } 1851 case TRANSIT_NONE: { 1852 return "TRANSIT_NONE"; 1853 } 1854 case TRANSIT_ACTIVITY_OPEN: { 1855 return "TRANSIT_ACTIVITY_OPEN"; 1856 } 1857 case TRANSIT_ACTIVITY_CLOSE: { 1858 return "TRANSIT_ACTIVITY_CLOSE"; 1859 } 1860 case TRANSIT_TASK_OPEN: { 1861 return "TRANSIT_TASK_OPEN"; 1862 } 1863 case TRANSIT_TASK_CLOSE: { 1864 return "TRANSIT_TASK_CLOSE"; 1865 } 1866 case TRANSIT_TASK_TO_FRONT: { 1867 return "TRANSIT_TASK_TO_FRONT"; 1868 } 1869 case TRANSIT_TASK_TO_BACK: { 1870 return "TRANSIT_TASK_TO_BACK"; 1871 } 1872 case TRANSIT_WALLPAPER_CLOSE: { 1873 return "TRANSIT_WALLPAPER_CLOSE"; 1874 } 1875 case TRANSIT_WALLPAPER_OPEN: { 1876 return "TRANSIT_WALLPAPER_OPEN"; 1877 } 1878 case TRANSIT_WALLPAPER_INTRA_OPEN: { 1879 return "TRANSIT_WALLPAPER_INTRA_OPEN"; 1880 } 1881 case TRANSIT_WALLPAPER_INTRA_CLOSE: { 1882 return "TRANSIT_WALLPAPER_INTRA_CLOSE"; 1883 } 1884 case TRANSIT_TASK_OPEN_BEHIND: { 1885 return "TRANSIT_TASK_OPEN_BEHIND"; 1886 } 1887 case TRANSIT_ACTIVITY_RELAUNCH: { 1888 return "TRANSIT_ACTIVITY_RELAUNCH"; 1889 } 1890 case TRANSIT_DOCK_TASK_FROM_RECENTS: { 1891 return "TRANSIT_DOCK_TASK_FROM_RECENTS"; 1892 } 1893 case TRANSIT_KEYGUARD_GOING_AWAY: { 1894 return "TRANSIT_KEYGUARD_GOING_AWAY"; 1895 } 1896 case TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER: { 1897 return "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER"; 1898 } 1899 case TRANSIT_KEYGUARD_OCCLUDE: { 1900 return "TRANSIT_KEYGUARD_OCCLUDE"; 1901 } 1902 case TRANSIT_KEYGUARD_UNOCCLUDE: { 1903 return "TRANSIT_KEYGUARD_UNOCCLUDE"; 1904 } 1905 default: { 1906 return "<UNKNOWN>"; 1907 } 1908 } 1909 } 1910 1911 private String appStateToString() { 1912 switch (mAppTransitionState) { 1913 case APP_STATE_IDLE: 1914 return "APP_STATE_IDLE"; 1915 case APP_STATE_READY: 1916 return "APP_STATE_READY"; 1917 case APP_STATE_RUNNING: 1918 return "APP_STATE_RUNNING"; 1919 case APP_STATE_TIMEOUT: 1920 return "APP_STATE_TIMEOUT"; 1921 default: 1922 return "unknown state=" + mAppTransitionState; 1923 } 1924 } 1925 1926 private String transitTypeToString() { 1927 switch (mNextAppTransitionType) { 1928 case NEXT_TRANSIT_TYPE_NONE: 1929 return "NEXT_TRANSIT_TYPE_NONE"; 1930 case NEXT_TRANSIT_TYPE_CUSTOM: 1931 return "NEXT_TRANSIT_TYPE_CUSTOM"; 1932 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE: 1933 return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE"; 1934 case NEXT_TRANSIT_TYPE_SCALE_UP: 1935 return "NEXT_TRANSIT_TYPE_SCALE_UP"; 1936 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: 1937 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP"; 1938 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: 1939 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN"; 1940 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP: 1941 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP"; 1942 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: 1943 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN"; 1944 default: 1945 return "unknown type=" + mNextAppTransitionType; 1946 } 1947 } 1948 1949 @Override 1950 public void dump(PrintWriter pw, String prefix) { 1951 pw.print(prefix); pw.println(this); 1952 pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString()); 1953 if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) { 1954 pw.print(prefix); pw.print("mNextAppTransitionType="); 1955 pw.println(transitTypeToString()); 1956 } 1957 switch (mNextAppTransitionType) { 1958 case NEXT_TRANSIT_TYPE_CUSTOM: 1959 pw.print(prefix); pw.print("mNextAppTransitionPackage="); 1960 pw.println(mNextAppTransitionPackage); 1961 pw.print(prefix); pw.print("mNextAppTransitionEnter=0x"); 1962 pw.print(Integer.toHexString(mNextAppTransitionEnter)); 1963 pw.print(" mNextAppTransitionExit=0x"); 1964 pw.println(Integer.toHexString(mNextAppTransitionExit)); 1965 break; 1966 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE: 1967 pw.print(prefix); pw.print("mNextAppTransitionPackage="); 1968 pw.println(mNextAppTransitionPackage); 1969 pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x"); 1970 pw.print(Integer.toHexString(mNextAppTransitionInPlace)); 1971 break; 1972 case NEXT_TRANSIT_TYPE_SCALE_UP: { 1973 getDefaultNextAppTransitionStartRect(mTmpRect); 1974 pw.print(prefix); pw.print("mNextAppTransitionStartX="); 1975 pw.print(mTmpRect.left); 1976 pw.print(" mNextAppTransitionStartY="); 1977 pw.println(mTmpRect.top); 1978 pw.print(prefix); pw.print("mNextAppTransitionStartWidth="); 1979 pw.print(mTmpRect.width()); 1980 pw.print(" mNextAppTransitionStartHeight="); 1981 pw.println(mTmpRect.height()); 1982 break; 1983 } 1984 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: 1985 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: 1986 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP: 1987 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: { 1988 pw.print(prefix); pw.print("mDefaultNextAppTransitionAnimationSpec="); 1989 pw.println(mDefaultNextAppTransitionAnimationSpec); 1990 pw.print(prefix); pw.print("mNextAppTransitionAnimationsSpecs="); 1991 pw.println(mNextAppTransitionAnimationsSpecs); 1992 pw.print(prefix); pw.print("mNextAppTransitionScaleUp="); 1993 pw.println(mNextAppTransitionScaleUp); 1994 break; 1995 } 1996 } 1997 if (mNextAppTransitionCallback != null) { 1998 pw.print(prefix); pw.print("mNextAppTransitionCallback="); 1999 pw.println(mNextAppTransitionCallback); 2000 } 2001 if (mLastUsedAppTransition != TRANSIT_NONE) { 2002 pw.print(prefix); pw.print("mLastUsedAppTransition="); 2003 pw.println(appTransitionToString(mLastUsedAppTransition)); 2004 pw.print(prefix); pw.print("mLastOpeningApp="); 2005 pw.println(mLastOpeningApp); 2006 pw.print(prefix); pw.print("mLastClosingApp="); 2007 pw.println(mLastClosingApp); 2008 } 2009 } 2010 2011 public void setCurrentUser(int newUserId) { 2012 mCurrentUserId = newUserId; 2013 } 2014 2015 /** 2016 * @return true if transition is not running and should not be skipped, false if transition is 2017 * already running 2018 */ 2019 boolean prepareAppTransitionLocked(int transit, boolean alwaysKeepCurrent, int flags, 2020 boolean forceOverride) { 2021 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:" 2022 + " transit=" + appTransitionToString(transit) 2023 + " " + this 2024 + " alwaysKeepCurrent=" + alwaysKeepCurrent 2025 + " Callers=" + Debug.getCallers(3)); 2026 if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet() 2027 || mNextAppTransition == TRANSIT_NONE) { 2028 setAppTransition(transit, flags); 2029 } else if (!alwaysKeepCurrent) { 2030 if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) { 2031 // Opening a new task always supersedes a close for the anim. 2032 setAppTransition(transit, flags); 2033 } else if (transit == TRANSIT_ACTIVITY_OPEN 2034 && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) { 2035 // Opening a new activity always supersedes a close for the anim. 2036 setAppTransition(transit, flags); 2037 } 2038 } 2039 boolean prepared = prepare(); 2040 if (isTransitionSet()) { 2041 mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT); 2042 mService.mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS); 2043 } 2044 return prepared; 2045 } 2046 2047 /** 2048 * @return true if {@param transit} is representing a transition in which Keyguard is going 2049 * away, false otherwise 2050 */ 2051 public static boolean isKeyguardGoingAwayTransit(int transit) { 2052 return transit == TRANSIT_KEYGUARD_GOING_AWAY 2053 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER; 2054 } 2055 2056 private static boolean isKeyguardTransit(int transit) { 2057 return isKeyguardGoingAwayTransit(transit) || transit == TRANSIT_KEYGUARD_OCCLUDE 2058 || transit == TRANSIT_KEYGUARD_UNOCCLUDE; 2059 } 2060 2061 /** 2062 * @return whether the transition should show the thumbnail being scaled down. 2063 */ 2064 private boolean shouldScaleDownThumbnailTransition(int uiMode, int orientation) { 2065 return mGridLayoutRecentsEnabled 2066 || orientation == Configuration.ORIENTATION_PORTRAIT; 2067 } 2068} 2069