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