目录
* 新活动中的窗口正在同一任务中的现有窗口之上打开。 int TRANSIT_ACTIVITY_OPEN = 6;
* 最顶层活动中的窗口正在关闭以显示同一任务中的前一个活动。 int TRANSIT_ACTIVITY_CLOSE = 7;
* 新任务中的窗口正在另一个活动任务中的现有窗口之上打开。 int TRANSIT_TASK_OPEN = 8;
* 最顶层活动中的一个窗口正在关闭,以显示不同任务中的前一个活动。 int TRANSIT_TASK_CLOSE = 9;
* 现有任务中的窗口显示在另一个活动任务中现有任务的顶部。 int TRANSIT_TASK_TO_FRONT = 10;
* 现有任务中的窗口被放置在所有其他任务下方。 int TRANSIT_TASK_TO_BACK = 11;
* Keyguard 即将消失。 int TRANSIT_KEYGUARD_GOING_AWAY = 20;
(1)AppTransitionController.handleAppTransitionReady 准备过渡动画
(2)AppTransitionController.applyAnimations 设置过渡动画
(3)WindowContainer.applyAnimation 启动动画
(4)WindowContainer.getAnimationAdapter 获取远程/窗口/应用过渡动画
(5)AppTransition.loadAnimation 获取动画实例
一.AppTransition过渡类型
* 未设置过渡。
int TRANSIT_UNSET = -1;
* 没有过渡动画。
int TRANSIT_NONE = 0;
* 新活动中的窗口正在同一任务中的现有窗口之上打开。
int TRANSIT_ACTIVITY_OPEN = 6;
* 最顶层活动中的窗口正在关闭以显示同一任务中的前一个活动。
int TRANSIT_ACTIVITY_CLOSE = 7;
* 新任务中的窗口正在另一个活动任务中的现有窗口之上打开。
int TRANSIT_TASK_OPEN = 8;
* 最顶层活动中的一个窗口正在关闭,以显示不同任务中的前一个活动。
int TRANSIT_TASK_CLOSE = 9;
* 现有任务中的窗口显示在另一个活动任务中现有任务的顶部。
int TRANSIT_TASK_TO_FRONT = 10;
* 现有任务中的窗口被放置在所有其他任务下方。
int TRANSIT_TASK_TO_BACK = 11;
* 新活动中没有墙纸的窗口会在有墙纸的窗口之上打开,从而有效地关闭墙纸。
int TRANSIT_WALLPAPER_CLOSE = 12;
* 新活动中带有墙纸的窗口会在没有墙纸的窗口上打开,从而有效地打开墙纸。
int TRANSIT_WALLPAPER_OPEN = 13;
* 新活动中的一个窗口在现有活动的顶部打开,并且两者都在墙纸的顶部。
int TRANSIT_WALLPAPER_INTRA_OPEN = 14;
* 最顶部活动中的窗口正在关闭以显示之前的活动,并且两者都位于墙纸的顶部。
int TRANSIT_WALLPAPER_INTRA_CLOSE = 15;
* 新任务中的一个窗口在另一个活动的任务中的现有窗口后面打开。新窗口将短暂显示,然后消失。
int TRANSIT_TASK_OPEN_BEHIND = 16;
* 正在重新启动活动(例如,由于配置更改)。
int TRANSIT_ACTIVITY_RELAUNCH = 18;
* 正在对接最近的任务。
int TRANSIT_DOCK_TASK_FROM_RECENTS = 19;
* Keyguard 即将消失。
int TRANSIT_KEYGUARD_GOING_AWAY = 20;
* Keyguard 将消失,显示背后请求墙纸的活动。
int TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21;
* Keyguard 被遮挡。
int TRANSIT_KEYGUARD_OCCLUDE = 22;
* Keyguard 未被遮挡。
int TRANSIT_KEYGUARD_UNOCCLUDE = 23;
* 正在打开一个半透明的活动。
int TRANSIT_TRANSLUCENT_ACTIVITY_OPEN = 24;
* 一个半透明的活动正在关闭。
int TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE = 25;
* 正在关闭崩溃的活动。
int TRANSIT_CRASHING_ACTIVITY_CLOSE = 26;
* 一项任务正在改变窗口模式
int TRANSIT_TASK_CHANGE_WINDOWING_MODE = 27;
* 由于第一个活动已启动或正在打开,因此正在显示只能包含一个任务的显示。
int TRANSIT_SHOW_SINGLE_TASK_DISPLAY = 28;
二.AppTransition设置过渡类型调用栈信息
* 新活动中的窗口正在同一任务中的现有窗口之上打开。
int TRANSIT_ACTIVITY_OPEN = 6;
(1)锁屏消失出现Activity时
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
com.android.server.wm.ActivityRecord.makeActiveIfNeeded
com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
com.android.server.wm.RootWindowContainer.applySleepTokens
com.android.server.wm.ActivityTaskManagerService.updateSleepIfNeededLocked
com.android.server.wm.RootWindowContainer.removeSleepToken
com.android.server.wm.RootWindowContainer.access$200
com.android.server.wm.RootWindowContainer$SleepTokenImpl.release
com.android.server.wm.KeyguardController$KeyguardDisplayState.releaseSleepToken
com.android.server.wm.KeyguardController.updateKeyguardSleepToken
com.android.server.wm.KeyguardController.updateKeyguardSleepToken
com.android.server.wm.KeyguardController.keyguardGoingAway
com.android.server.wm.ActivityTaskManagerService.keyguardGoingAway
android.app.IActivityTaskManager$Stub.onTransact
(2)应用中进入新的Activity时
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityStack.startActivityLocked
com.android.server.wm.ActivityStarter.startActivityInner
com.android.server.wm.ActivityStarter.startActivityUnchecked
com.android.server.wm.ActivityStarter.executeRequest
com.android.server.wm.ActivityStarter.execute
com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
com.android.server.wm.ActivityTaskManagerService.startActivity
android.app.IActivityTaskManager$Stub.onTransact
(3)应用中新的Activity OnResume时
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
com.android.server.wm.ActivityStack.completePauseLocked
com.android.server.wm.ActivityRecord.activityPaused
com.android.server.wm.ActivityTaskManagerService.activityPaused
android.app.IActivityTaskManager$Stub.onTransact
(4)前台应用被杀死时,需要显示的Activity OnResume时
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
com.android.server.wm.ActivityRecord.makeActiveIfNeeded
com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
com.android.server.wm.ActivityTaskManagerService$LocalService.handleAppDied
com.android.server.am.ActivityManagerService.handleAppDiedLocked
com.android.server.am.ActivityManagerService.appDiedLocked
com.android.server.am.ActivityManagerService$AppDeathRecipient.binderDied
* 最顶层活动中的窗口正在关闭以显示同一任务中的前一个活动。
int TRANSIT_ACTIVITY_CLOSE = 7;
(1)应用中按back键推出Activity时
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityRecord.finishIfPossible
com.android.server.wm.ActivityTaskManagerService.finishActivity
android.app.IActivityTaskManager$Stub.onTransact
(2)应用中按back键需要显示的Activity OnResume时
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
com.android.server.wm.ActivityStack.completePauseLocked
com.android.server.wm.ActivityRecord.activityPaused
com.android.server.wm.ActivityTaskManagerService.activityPaused
android.app.IActivityTaskManager$Stub.onTransact
* 新任务中的窗口正在另一个活动任务中的现有窗口之上打开。
int TRANSIT_TASK_OPEN = 8;
(1)进入新的堆栈,新的Activity启动时
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityStack.startActivityLocked
com.android.server.wm.ActivityStarter.startActivityInner
com.android.server.wm.ActivityStarter.startActivityUnchecked
com.android.server.wm.ActivityStarter.executeRequest
com.android.server.wm.ActivityStarter.execute
com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
com.android.server.wm.ActivityTaskManagerService.startActivity
android.app.IActivityTaskManager$Stub.onTransact
(2)进入新的堆栈,新的Activity OnResume时
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
com.android.server.wm.ActivityStack.completePauseLocked
com.android.server.wm.ActivityRecord.activityPaused
com.android.server.wm.ActivityTaskManagerService.activityPaused
android.app.IActivityTaskManager$Stub.onTransact
* 最顶层活动中的一个窗口正在关闭,以显示不同任务中的前一个活动。
int TRANSIT_TASK_CLOSE = 9;
(1)应用中按back键推出Activity堆栈时
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityRecord.finishIfPossible
com.android.server.wm.ActivityTaskManagerService.finishActivity
android.app.IActivityTaskManager$Stub.onTransact
(2)应用中按back键新的堆栈Activity OnResume时
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
com.android.server.wm.ActivityStack.completePauseLocked
com.android.server.wm.ActivityRecord.activityPaused
com.android.server.wm.ActivityTaskManagerService.activityPaused
android.app.IActivityTaskManager$Stub.onTransact
* 现有任务中的窗口显示在另一个活动任务中现有任务的顶部。
int TRANSIT_TASK_TO_FRONT = 10;
(1)最近任务进入已有的堆栈
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityStack.updateTransitLocked
com.android.server.wm.ActivityStack.moveTaskToFront
com.android.server.wm.ActivityStack.moveTaskToFront
com.android.server.wm.ActivityStackSupervisor.findTaskToMoveToFront
com.android.server.wm.ActivityTaskManagerService.moveTaskToFrontLocked
com.android.server.wm.ActivityStackSupervisor.startActivityFromRecents
com.android.server.wm.ActivityTaskManagerService.startActivityFromRecents
android.app.IActivityTaskManager$Stub.onTransact
(2)桌面点击进入已有的堆栈
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityStack.updateTransitLocked
com.android.server.wm.ActivityStack.moveTaskToFront
com.android.server.wm.ActivityStarter.setTargetStackIfNeeded
com.android.server.wm.ActivityStarter.recycleTask
com.android.server.wm.ActivityStarter.startActivityInner
com.android.server.wm.ActivityStarter.startActivityUnchecked
com.android.server.wm.ActivityStarter.executeRequest
com.android.server.wm.ActivityStarter.execute
com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
com.android.server.wm.ActivityTaskManagerService.startActivity
android.app.IActivityTaskManager$Stub.onTransact
(3)应用中点击Home键时
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityStack.updateTransitLocked
com.android.server.wm.ActivityStack.moveTaskToFront
com.android.server.wm.ActivityStarter.setTargetStackIfNeeded
com.android.server.wm.ActivityStarter.recycleTask
com.android.server.wm.ActivityStarter.startActivityInner
com.android.server.wm.ActivityStarter.startActivityUnchecked
com.android.server.wm.ActivityStarter.executeRequest
com.android.server.wm.ActivityStarter.execute
com.android.server.wm.ActivityStartController.startHomeActivity
com.android.server.wm.RootWindowContainer.startHomeOnTaskDisplayArea
com.android.server.wm.RootWindowContainer.startHomeOnDisplay
com.android.server.wm.ActivityTaskManagerService$LocalService.startHomeOnDisplay
com.android.server.policy.PhoneWindowManager.startDockOrHome
com.android.server.policy.PhoneWindowManager.launchHomeFromHotKey
com.android.server.policy.PhoneWindowManager.launchHomeFromHotKey
com.android.server.policy.PhoneWindowManager.handleShortPressOnHome
com.android.server.policy.PhoneWindowManager.access$2700
com.android.server.policy.PhoneWindowManager$DisplayHomeButtonHandler.lambda$handleHomeButton$0$PhoneWindowManager$DisplayHomeButtonHandler
* 现有任务中的窗口被放置在所有其他任务下方。
int TRANSIT_TASK_TO_BACK = 11;
(1)应用主动调用Activity.moveTaskToBack()时出现(这个方法不会改变task中的activity中的顺序,效果基本等同于home键)
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.ActivityStack.moveTaskToBack
com.android.server.wm.ActivityTaskManagerService.moveActivityTaskToBack
android.app.IActivityTaskManager$Stub.onTransact
* Keyguard 即将消失。
int TRANSIT_KEYGUARD_GOING_AWAY = 20;
com.android.server.wm.DisplayContent.prepareAppTransition
com.android.server.wm.KeyguardController.keyguardGoingAway
com.android.server.wm.ActivityTaskManagerService.keyguardGoingAway
android.app.IActivityTaskManager$Stub.onTransact
注意:有时会一次Activity切换时会出现多个过渡类型的设置,例如startActivity时会设置一个,Activity OnResume时会出现一次,所以真正的过渡类型,还需要AppTransition.prepareAppTransitionLocked筛选。
/**
* @return true if transition is not running and should not be skipped, false if transition is
* already running
*/
boolean prepareAppTransitionLocked(@TransitionType int transit, boolean alwaysKeepCurrent,
@TransitionFlags int flags, boolean forceOverride) {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d "
+ "Callers=%s",
appTransitionToString(transit), this, alwaysKeepCurrent,
mDisplayContent.getDisplayId(), Debug.getCallers(20));
final boolean allowSetCrashing = !isKeyguardTransit(mNextAppTransition)
&& transit == TRANSIT_CRASHING_ACTIVITY_CLOSE;
if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet()
|| mNextAppTransition == TRANSIT_NONE || allowSetCrashing) {
setAppTransition(transit, flags);
}
// We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
// relies on the fact that we always execute a Keyguard transition after preparing one. We
// also don't want to change away from a crashing transition.
else if (!alwaysKeepCurrent && !isKeyguardTransit(mNextAppTransition)
&& mNextAppTransition != TRANSIT_CRASHING_ACTIVITY_CLOSE) {
if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
// Opening a new task always supersedes a close for the anim.
setAppTransition(transit, flags);
} else if (transit == TRANSIT_ACTIVITY_OPEN
&& isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
// Opening a new activity always supersedes a close for the anim.
setAppTransition(transit, flags);
} else if (isTaskTransit(transit) && isActivityTransit(mNextAppTransition)) {
// Task animations always supersede activity animations, because if we have both, it
// usually means that activity transition were just trampoline activities.
setAppTransition(transit, flags);
}
}
boolean prepared = prepare();
if (isTransitionSet()) {
removeAppTransitionTimeoutCallbacks();
mHandler.postDelayed(mHandleAppTransitionTimeoutRunnable, APP_TRANSITION_TIMEOUT_MS);
}
return prepared;
}
三.AppTransition 执行前的调用栈信息
DisplayContent中是应用过渡转化的过程:
void executeAppTransition() {
if (mAppTransition.isTransitionSet()) {
ProtoLog.w(WM_DEBUG_APP_TRANSITIONS,
"Execute app transition: %s, displayId: %d Callers=%s",
mAppTransition, mDisplayId, Debug.getCallers(20));
mAppTransition.setReady();
mWmService.mWindowPlacerLocked.requestTraversal();
}
}
此过程会设置AppTransition的状态为准备状态,同时调用WindowSurfacePlacer.requestTraversal对WMS状态做刷新。
(1)非冷启动应用
com.android.server.wm.RootWindowContainer.executeAppTransitionForAllDisplay
com.android.server.wm.ActivityStackSupervisor.reportResumedActivityLocked
com.android.server.wm.ActivityRecord.completeResumeLocked
com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
com.android.server.wm.ActivityStack.completePauseLocked
com.android.server.wm.ActivityRecord.activityPaused
com.android.server.wm.ActivityTaskManagerService.activityPaused
android.app.IActivityTaskManager$Stub.onTransact
(2)锁屏消失时
com.android.server.wm.WindowManagerService.executeAppTransition
com.android.server.wm.KeyguardController.keyguardGoingAway
com.android.server.wm.ActivityTaskManagerService.keyguardGoingAway
android.app.IActivityTaskManager$Stub.onTransact
(3)最近任务显示已有堆栈的Actiivty
com.android.server.wm.RootWindowContainer.executeAppTransitionForAllDisplay
com.android.server.wm.ActivityStackSupervisor.reportResumedActivityLocked
com.android.server.wm.ActivityRecord.completeResumeLocked
com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
com.android.server.wm.ActivityStarter.resumeTargetStackIfNeeded
com.android.server.wm.ActivityStarter.recycleTask
com.android.server.wm.ActivityStarter.startActivityInner
com.android.server.wm.ActivityStarter.startActivityUnchecked
com.android.server.wm.ActivityStarter.executeRequest
com.android.server.wm.ActivityStarter.execute
com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
com.android.server.wm.ActivityTaskManagerService.startActivity
android.app.IActivityTaskManager$Stub.onTransact
(4)冷启动应用
com.android.server.wm.RootWindowContainer.executeAppTransitionForAllDisplay
com.android.server.wm.ActivityStackSupervisor.reportResumedActivityLocked
com.android.server.wm.ActivityRecord.completeResumeLocked
com.android.server.wm.ActivityStack.minimalResumeActivityLocked
com.android.server.wm.ActivityStackSupervisor.realStartActivityLocked
com.android.server.wm.RootWindowContainer.startActivityForAttachedApplicationIfNeeded
com.android.server.wm.RootWindowContainer.lambda$5fbF65VSmaJkPHxEhceOGTat7JE
com.android.server.wm.-$$Lambda$RootWindowContainer$5fbF65VSmaJkPHxEhceOGTat7JE.apply
com.android.internal.util.function.pooled.PooledLambdaImpl.doInvoke
com.android.internal.util.function.pooled.PooledLambdaImpl.invoke
com.android.internal.util.function.pooled.OmniFunction.apply
com.android.server.wm.ActivityRecord.forAllActivities
com.android.server.wm.WindowContainer.forAllActivities
com.android.server.wm.WindowContainer.forAllActivities
com.android.server.wm.RootWindowContainer.attachApplication
com.android.server.wm.ActivityTaskManagerService$LocalService.attachApplication
com.android.server.am.ActivityManagerService.attachApplicationLocked
com.android.server.am.ActivityManagerService.attachApplication
android.app.IActivityManager$Stub.onTransact
com.android.server.am.ActivityManagerService.onTransact
四.AppTransition的过渡动画的启动
com.android.server.wm.RootWindowContainer.checkAppTransitionReady
com.android.server.wm.RootWindowContainer.performSurfacePlacement
com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop
com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement
private void checkAppTransitionReady(WindowSurfacePlacer surfacePlacer) {
// Trace all displays app transition by Z-order for pending layout change.
for (int i = mChildren.size() - 1; i >= 0; --i) {
final DisplayContent curDisplay = mChildren.get(i);
// If we are ready to perform an app transition, check through all of the app tokens
// to be shown and see if they are ready to go.
if (curDisplay.mAppTransition.isReady()) {
// handleAppTransitionReady may modify curDisplay.pendingLayoutChanges.
curDisplay.mAppTransitionController.handleAppTransitionReady();
if (DEBUG_LAYOUT_REPEATS) {
surfacePlacer.debugLayoutRepeats("after handleAppTransitionReady",
curDisplay.pendingLayoutChanges);
}
}
if (curDisplay.mAppTransition.isRunning() && !curDisplay.isAppTransitioning()) {
// We have finished the animation of an app transition. To do this, we have
// delayed a lot of operations like showing and hiding apps, moving apps in
// Z-order, etc.
// The app token list reflects the correct Z-order, but the window list may now
// be out of sync with it. So here we will just rebuild the entire app window
// list. Fun!
curDisplay.handleAnimatingStoppedAndTransition();
if (DEBUG_LAYOUT_REPEATS) {
surfacePlacer.debugLayoutRepeats("after handleAnimStopAndXitionLock",
curDisplay.pendingLayoutChanges);
}
}
}
}
如上源码,checkAppTransitionReady会判断DisplayContent的AppTransition是否处于准备状态,处于准备状态的时候就调用AppTransitionController.handleAppTransitionReady。
(1)AppTransitionController.handleAppTransitionReady 准备过渡动画
/**
* Handle application transition for given display.
*/
void handleAppTransitionReady() {
mTempTransitionReasons.clear();
/* 对即将打开或者改变的组件做判断是否需要开始过渡
主要有:屏幕旋转时推迟,组件未准备好时推迟,远程动画时推迟,壁纸未准备好时推迟 */
if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
|| !transitionGoodToGo(mDisplayContent.mChangingContainers,
mTempTransitionReasons)) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "**** GOOD TO GO");
/*判断是否需要跳过过渡
*/
final AppTransition appTransition = mDisplayContent.mAppTransition;
int transit = appTransition.getAppTransition();
if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
transit = WindowManager.TRANSIT_UNSET;
}
/*清理环境属性
*/
mDisplayContent.mSkipAppTransitionAnimation = false;
mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
appTransition.removeAppTransitionTimeoutCallbacks();
mDisplayContent.mWallpaperMayChange = false;
/*清理发生变化的组件的动画属性
*/
int appCount = mDisplayContent.mOpeningApps.size();
for (int i = 0; i < appCount; ++i) {
// Clearing the mAnimatingExit flag before entering animation. It's set to true if app
// window is removed, or window relayout to invisible. This also affects window
// visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
// transition selection depends on wallpaper target visibility.
mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
}
appCount = mDisplayContent.mChangingContainers.size();
for (int i = 0; i < appCount; ++i) {
// Clearing for same reason as above.
final ActivityRecord activity = getAppFromContainer(
mDisplayContent.mChangingContainers.valueAtUnchecked(i));
if (activity != null) {
activity.clearAnimatingFlags();
}
}
/*通过变化的组件对壁纸调整
*/
// Adjust wallpaper before we pull the lower/upper target, since pending changes
// (like the clearAnimatingFlags() above) might affect wallpaper target result.
// Or, the opening app window should be a wallpaper target.
mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
mDisplayContent.mOpeningApps);
/*变化的组件为壁纸目标时
*/
// Determine if closing and opening app token sets are wallpaper targets, in which case
// special animations are needed.
final boolean hasWallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget() != null;
final boolean openingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mOpeningApps)
&& hasWallpaperTarget;
final boolean closingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mClosingApps)
&& hasWallpaperTarget;
/*变化的组件为透明时做特殊处理
TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE
TRANSIT_TRANSLUCENT_ACTIVITY_OPEN
*/
transit = maybeUpdateTransitToTranslucentAnim(transit);
/*变化的组件为壁纸目标时做特殊处理,改变过渡方式
TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER
TRANSIT_WALLPAPER_INTRA_OPEN
TRANSIT_WALLPAPER_INTRA_CLOSE
TRANSIT_WALLPAPER_CLOSE
TRANSIT_WALLPAPER_OPEN
*/
transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
closingAppHasWallpaper);
// Find the layout params of the top-most application window in the tokens, which is
// what will control the animation theme. If all closing windows are obscured, then there is
// no need to do an animation. This is the case, for example, when this transition is being
// done behind a dream window.
/*获取各个变化的组件的TOP,适配远程动画
*/
final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers);
final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes);
final ActivityRecord topOpeningApp =
getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */);
final ActivityRecord topClosingApp =
getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */);
final ActivityRecord topChangingApp =
getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
/*获取变化组件是否为语音交互
咦! ||前后两个函数参数都相同
*/
final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
|| containsVoiceInteraction(mDisplayContent.mOpeningApps);
/*暂停系统界面动画,开始设置过渡动画
*/
final int layoutRedo;
mService.mSurfaceAnimationRunner.deferStartingAnimations();
try {
/*对待关闭/待打开的组件启动过渡动画,此函数较复杂,下面会有详细说明:
*/
applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit,
animLp, voiceInteraction);
/*处理待关闭的组件,设置其属性使,其满足运行过渡动画的条件:
*/
handleClosingApps();
/*处理待打开的组件,设置其属性使,其满足运行过渡动画的条件:
*/
handleOpeningApps();
/*对待改变的窗口启动过渡动画,流程上和上面applyAnimations会有重合
*/
handleChangingApps(transit);
/*设置AppTransition最新属性
*/
appTransition.setLastAppTransition(transit, topOpeningApp,
topClosingApp, topChangingApp);
/*AppTransition通知监听者是否需要重新布局
*/
final int flags = appTransition.getTransitFlags();
layoutRedo = appTransition.goodToGo(transit, topOpeningApp,
mDisplayContent.mOpeningApps);
/*针对非应用基础组件的窗口的过渡动画,如壁纸,状态栏,虚拟按键,悬浮窗等
*/
handleNonAppWindowsInTransition(transit, flags);
/*清理环境属性
*/
appTransition.postAnimationCallback();
appTransition.clear();
} finally {
/*恢复系统界面动画
*/
mService.mSurfaceAnimationRunner.continueStartingAnimations();
}
/*系统缩略图界面动画
*/
mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
/*清理环境属性
*/
mDisplayContent.mOpeningApps.clear();
mDisplayContent.mClosingApps.clear();
mDisplayContent.mChangingContainers.clear();
mDisplayContent.mUnknownAppVisibilityController.clear();
// This has changed the visibility of windows, so perform
// a new layout to get them all up-to-date.
mDisplayContent.setLayoutNeeded();
/*重新计算输入法目标窗口
*/
mDisplayContent.computeImeTarget(true /* updateImeTarget */);
mService.mAtmService.mStackSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
mTempTransitionReasons);
if (transit == TRANSIT_SHOW_SINGLE_TASK_DISPLAY) {
mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
mService.mAtmInternal.notifySingleTaskDisplayDrawn(mDisplayContent.getDisplayId());
});
}
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
mDisplayContent.pendingLayoutChanges |=
layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
}
(2)AppTransitionController.applyAnimations 设置过渡动画
/*
* @param openingApps 应用过渡动画的打开应用列表。
* @param closedApps 应用程序过渡动画所应用的关闭应用程序列表。
* @param trans 当前过渡类型。
* @param animLp 应用程序过渡动画在其中运行的布局参数。
* @param voiceInteraction {@code true} 如果此转换中的应用程序之一属于语音交互会话驱动任务。
被handleAppTransitionReady调用
*/
private void applyAnimations(ArraySet<ActivityRecord> openingApps,
ArraySet<ActivityRecord> closingApps, @TransitionType int transit,
LayoutParams animLp, boolean voiceInteraction) {
/*跳过应用动画
*/
if (transit == WindowManager.TRANSIT_UNSET
|| (openingApps.isEmpty() && closingApps.isEmpty())) {
return;
}
/*获取openingApps过渡动画的目标,会根据其openingApps和closingApps的关系,向上找寻父类,直到同一父类时停止
同一应用时为ActivityRecord
不同应用时为Task
解锁时无closingApps则为DefaultTaskDisplayArea
*/
final ArraySet<WindowContainer> openingWcs = getAnimationTargets(
openingApps, closingApps, true /* visible */);
/*获取closingApps过渡动画的目标,会根据其openingApps和closingApps的关系,向上找寻父类,直到同一父类时停止
同一应用时为ActivityRecord
不同应用时为Task
解锁时无closingApps则为DefaultTaskDisplayArea
*/
final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
openingApps, closingApps, false /* visible */);
/*将过渡动画应用于openingWcs
*/
applyAnimations(openingWcs, openingApps, transit, true /* visible */, animLp,
voiceInteraction);
/*将过渡动画应用于closingWcs
*/
applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp,
voiceInteraction);
final AccessibilityController accessibilityController =
mDisplayContent.mWmService.mAccessibilityController;
if (accessibilityController != null) {
accessibilityController.onAppWindowTransitionLocked(
mDisplayContent.getDisplayId(), transit);
}
}
/*将过渡动画应用于目标容器
*/
private void applyAnimations(ArraySet<WindowContainer> wcs, ArraySet<ActivityRecord> apps,
@TransitionType int transit, boolean visible, LayoutParams animLp,
boolean voiceInteraction) {
final int wcsCount = wcs.size();
for (int i = 0; i < wcsCount; i++) {
final WindowContainer wc = wcs.valueAt(i);
// If app transition animation target is promoted to higher level, SurfaceAnimator
// triggers WC#onAnimationFinished only on the promoted target. So we need to take care
// of triggering AR#onAnimationFinished on each ActivityRecord which is a part of the
// app transition.
/*目标组件可能会被抬升至较高级的组件(如:DefaultTaskDisplayArea),onAnimationFinished只会传递到最高的组件
无法向下传播,故添加目标至高级的组件中使其能够调用到onAnimationFinished
*/
final ArrayList<ActivityRecord> transitioningDescendants = new ArrayList<>();
for (int j = 0; j < apps.size(); ++j) {
final ActivityRecord app = apps.valueAt(j);
if (app.isDescendantOf(wc)) {
transitioningDescendants.add(app);
}
}
/*目标组件应用过渡动画
(applyAnimation函数不仅在WindowContainer实现,
也在ActivityRecord中实现了,ActivityRecord是涉及到StartingWindow,此处就不分析了)
*/
wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants);
}
}
(3)WindowContainer.applyAnimation 启动动画
/*
* 根据窗口层次结构中给定的布局属性应用过渡动画。
*
* @param lp 窗口的布局参数。
* @param trans 应用程序转换类型指示要应用的转换类型。
* @param enter 应用过渡是否进入过渡(visible)。
* @param isVoiceInteraction 容器是否参与语音交互。
* @param sources {@link ActivityRecord}s which causes this app transition animation.
*
* @return {@code true} 当容器应用应用转换时,{@code false} 如果应用转换被禁用或跳过。
被AppTransitionController.applyAnimations调用
*/
boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) {
/*系统级的关闭过渡动画
*/
if (mWmService.mDisableTransitionAnimation) {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: transition animation is disabled or skipped. "
+ "container=%s", this);
cancelAnimation();
return false;
}
// Only apply an animation if the display isn't frozen. If it is frozen, there is no reason
// to animate and it can cause strange artifacts when we unfreeze the display if some
// different animation is running.
/*屏幕固定时不允许过渡动画
*/
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation");
if (okToAnimate()) {
applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
} else {
cancelAnimation();
}
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
return isAnimating();
}
protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
int transit, boolean isVoiceInteraction,
@Nullable ArrayList<WindowContainer> sources) {
/*获取两个动画元素,一个用于普通动画,另一个用于缩略图动画
*/
final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
transit, enter, isVoiceInteraction);
/*普通动画
*/
AnimationAdapter adapter = adapters.first;
/*缩略图动画
*/
AnimationAdapter thumbnailAdapter = adapters.second;
if (adapter != null) {
/*添加onAnimationFinished回调
*/
if (sources != null) {
mSurfaceAnimationSources.addAll(sources);
}
/*在容器上启动动画
*/
startAnimation(getPendingTransaction(), adapter, !isVisible(),
ANIMATION_TYPE_APP_TRANSITION);
/*在动画期间需要显示壁纸
*/
if (adapter.getShowWallpaper()) {
getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
/*启动缩略图动画
*/
if (thumbnailAdapter != null) {
mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(),
thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION, (type, anim) -> { });
}
}
}
(4)WindowContainer.getAnimationAdapter 获取远程/窗口/应用过渡动画
Pair<AnimationAdapter, AnimationAdapter> getAnimationAdapter(WindowManager.LayoutParams lp,
int transit, boolean enter, boolean isVoiceInteraction) {
final Pair<AnimationAdapter, AnimationAdapter> resultAdapters;
/*在动画期间窗口如何被堆栈边界裁剪
*/
final int appStackClipMode = getDisplayContent().mAppTransition.getAppStackClipMode();
// Separate position and size for use in animators.
/*在动画期间的位置和大小
*/
final Rect screenBounds = getAnimationBounds(appStackClipMode);
mTmpRect.set(screenBounds);
getAnimationPosition(mTmpPoint);
if (!sHierarchicalAnimations) {
// Non-hierarchical animation uses position in global coordinates.
mTmpPoint.set(mTmpRect.left, mTmpRect.top);
}
mTmpRect.offsetTo(0, 0);
/*远程过渡动画
*/
final RemoteAnimationController controller =
getDisplayContent().mAppTransition.getRemoteAnimationController();
/*改变窗口的过渡动画
*/
final boolean isChanging = AppTransition.isChangeTransit(transit) && enter
&& isChangingAppTransition();
/*远程过渡动画,如通过Launcher3点击启动应用事,Launcher3会优先设置RemoteAnimationController
*/
// Delaying animation start isn't compatible with remote animations at all.
if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) {
final Rect localBounds = new Rect(mTmpRect);
localBounds.offsetTo(mTmpPoint.x, mTmpPoint.y);
final RemoteAnimationController.RemoteAnimationRecord adapters =
controller.createRemoteAnimationRecord(this, mTmpPoint, localBounds,
screenBounds, (isChanging ? mSurfaceFreezer.mFreezeBounds : null));
resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
/*改变窗口的过渡动画
*/
} else if (isChanging) {
final float durationScale = mWmService.getTransitionAnimationScaleLocked();
final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y);
final AnimationAdapter adapter = new LocalAnimationAdapter(
new WindowChangeAnimationSpec(mSurfaceFreezer.mFreezeBounds, mTmpRect,
displayInfo, durationScale, true /* isAppAnimation */,
false /* isThumbnail */),
getSurfaceAnimationRunner());
final AnimationAdapter thumbnailAdapter = mSurfaceFreezer.mSnapshot != null
? new LocalAnimationAdapter(new WindowChangeAnimationSpec(
mSurfaceFreezer.mFreezeBounds, mTmpRect, displayInfo, durationScale,
true /* isAppAnimation */, true /* isThumbnail */), getSurfaceAnimationRunner())
: null;
resultAdapters = new Pair<>(adapter, thumbnailAdapter);
mTransit = transit;
mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
} else {
/*是否需要创建 mAnimationBoundsLayer 来裁剪动画
*/
mNeedsAnimationBoundsLayer = (appStackClipMode == STACK_CLIP_AFTER_ANIM);
/*装载合适的过渡动画
*/
final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
if (a != null) {
// Only apply corner radius to animation if we're not in multi window mode.
// We don't want rounded corners when in pip or split screen.
final float windowCornerRadius = !inMultiWindowMode()
? getDisplayContent().getWindowCornerRadius()
: 0;
AnimationAdapter adapter = new LocalAnimationAdapter(
new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
getDisplayContent().mAppTransition.canSkipFirstFrame(),
appStackClipMode, true /* isAppAnimation */, windowCornerRadius),
getSurfaceAnimationRunner());
resultAdapters = new Pair<>(adapter, null);
mNeedsZBoost = a.getZAdjustment() == Animation.ZORDER_TOP
|| AppTransition.isClosingTransit(transit);
mTransit = transit;
mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
} else {
resultAdapters = new Pair<>(null, null);
}
}
return resultAdapters;
}
private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
boolean isVoiceInteraction) {
if (isOrganized()) {
// Defer to the task organizer to run animations
return null;
}
/*显示信息
*/
final DisplayContent displayContent = getDisplayContent();
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final int width = displayInfo.appWidth;
final int height = displayInfo.appHeight;
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: container=%s", this);
// Determine the visible rect to calculate the thumbnail clip with
// getAnimationFrames.
/* frame 进入动画结束或退出动画开始的边界。
insets 被系统窗口覆盖的边界。
stableInsets 确定稳定系统窗口覆盖的区域的边界。
surfaceInsets 绘图表面和窗口内容之间的交集。
*/
final Rect frame = new Rect(0, 0, width, height);
final Rect displayFrame = new Rect(0, 0,
displayInfo.logicalWidth, displayInfo.logicalHeight);
final Rect insets = new Rect();
final Rect stableInsets = new Rect();
final Rect surfaceInsets = new Rect();
getAnimationFrames(frame, insets, stableInsets, surfaceInsets);
/*
*/
if (mLaunchTaskBehind) {
// Differentiate the two animations. This one which is briefly on the screen
// gets the !enter animation, and the other one which remains on the
// screen gets the enter animation. Both appear in the mOpeningApps set.
enter = false;
}
ProtoLog.d(WM_DEBUG_APP_TRANSITIONS,
"Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s "
+ "surfaceInsets=%s",
AppTransition.appTransitionToString(transit), enter, frame, insets, surfaceInsets);
/*获取过渡动画,指向了AppTransition.loadAnimation,会单独开一小节分析源码
*/
final Configuration displayConfig = displayContent.getConfiguration();
final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter,
displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets,
surfaceInsets, stableInsets, isVoiceInteraction, inFreeformWindowingMode(), this);
if (a != null) {
if (a != null) {
// Setup the maximum app transition duration to prevent malicious app may set a long
// animation duration or infinite repeat counts for the app transition through
// ActivityOption#makeCustomAnimation or WindowManager#overridePendingTransition.
a.restrictDuration(MAX_APP_TRANSITION_DURATION);
}
if (DEBUG_ANIM) {
logWithStack(TAG, "Loaded animation " + a + " for " + this
+ ", duration: " + ((a != null) ? a.getDuration() : 0));
}
final int containingWidth = frame.width();
final int containingHeight = frame.height();
/*设置动画的目标的尺寸以及目标的父项的尺寸来初始化。(支持相对于这些尺寸指定的动画尺寸)
*/
a.initialize(containingWidth, containingHeight, width, height);
a.scaleCurrentDuration(mWmService.getTransitionAnimationScaleLocked());
}
return a;
}
(5)AppTransition.loadAnimation 获取动画实例
Animation loadAnimation(LayoutParams lp, int transit, boolean enter, int uiMode,
int orientation, Rect frame, Rect displayFrame, Rect insets,
@Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
boolean freeform, WindowContainer container) {
Animation a;
/*锁屏消失时,进入应用界面的动画(包括两种,即将显示壁纸和不显示壁纸应用)*/
if (isKeyguardGoingAwayTransit(transit) && enter) {
a = loadKeyguardExitAnimation(transit);
/*锁屏进入安全界面(紧急拨号,或者相机)时动画为无,一般此时动画由SystemUI处理*/
} else if (transit == TRANSIT_KEYGUARD_OCCLUDE) {
a = null;
/*从安全界面进入锁屏的动画,针对的退出应用动画*/
} else if (transit == TRANSIT_KEYGUARD_UNOCCLUDE && !enter) {
a = loadAnimationRes(lp, com.android.internal.R.anim.wallpaper_open_exit);
/*应用崩溃时动画为无*/
} else if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
a = null;
/*语音界面,进入前台时的动画*/
} else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
|| transit == TRANSIT_TASK_OPEN
|| transit == TRANSIT_TASK_TO_FRONT)) {
a = loadAnimationRes(lp, enter
? com.android.internal.R.anim.voice_activity_open_enter
: com.android.internal.R.anim.voice_activity_open_exit);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,
appTransitionToString(transit), enter, Debug.getCallers(3));
/*语音界面,退出时的动画*/
} else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
|| transit == TRANSIT_TASK_CLOSE
|| transit == TRANSIT_TASK_TO_BACK)) {
a = loadAnimationRes(lp, enter
? com.android.internal.R.anim.voice_activity_close_enter
: com.android.internal.R.anim.voice_activity_close_exit);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,
appTransitionToString(transit), enter, Debug.getCallers(3));
/*Actiivty重新启动的动画,如配置修改时的重启*/
} else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
a = createRelaunchAnimation(frame, insets);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s", a,
mNextAppTransition, appTransitionToString(transit),
Debug.getCallers(3));
/*ActivityOptions(ANIM_CUSTOM)相关过渡动画 ,或者Actiivty.overridePendingTransition设置的过渡动画*/
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
a = loadAnimationRes(mNextAppTransitionPackage, enter ?
mNextAppTransitionEnter : mNextAppTransitionExit);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s "
+ "isEntrance=%b Callers=%s",
a, appTransitionToString(transit), enter, Debug.getCallers(3));
setAppTransitionFinishedCallbackIfNeeded(a);
/*ActivityOptions 相关过渡动画*/
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE "
+ "transit=%s Callers=%s",
a, appTransitionToString(transit), Debug.getCallers(3));
/*ActivityOptions(ANIM_CLIP_REVEAL)相关过渡动画*/
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL "
+ "transit=%s Callers=%s",
a, appTransitionToString(transit), Debug.getCallers(3));
/*ActivityOptions(ANIM_SCALE_UP)相关过渡动画*/
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
a = createScaleUpAnimationLocked(transit, enter, frame);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s "
+ "isEntrance=%s Callers=%s",
a, appTransitionToString(transit), enter, Debug.getCallers(3));
/*ActivityOptions(ANIM_THUMBNAIL_SCALE_UP/ANIM_THUMBNAIL_SCALE_DOWN)相关过渡动画*/
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
mNextAppTransitionScaleUp =
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
frame, transit, container);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
+ "Callers=%s",
a, mNextAppTransitionScaleUp
? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN",
appTransitionToString(transit), enter, Debug.getCallers(3));
/*ActivityOptions(ANIM_THUMBNAIL_ASPECT_SCALE_UP/ANIM_THUMBNAIL_ASPECT_SCALE_DOWN)相关过渡动画*/
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
mNextAppTransitionScaleUp =
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
a = createAspectScaledThumbnailEnterExitAnimationLocked(
getThumbnailTransitionState(enter), uiMode, orientation, transit, frame,
insets, surfaceInsets, stableInsets, freeform, container);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
+ "Callers=%s",
a, mNextAppTransitionScaleUp
? "ANIM_THUMBNAIL_ASPECT_SCALE_UP"
: "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN",
appTransitionToString(transit), enter, Debug.getCallers(3));
/*ActivityOptions(ANIM_OPEN_CROSS_PROFILE_APPS)相关过渡动画*/
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS && enter) {
a = loadAnimationRes("android",
com.android.internal.R.anim.task_open_enter_cross_profile_apps);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: "
+ "anim=%s transit=%s isEntrance=true Callers=%s",
a, appTransitionToString(transit), Debug.getCallers(3));
/*Activity WindowMode发生变化时,如自由模式变化为全屏模式*/
} else if (transit == TRANSIT_TASK_CHANGE_WINDOWING_MODE) {
// In the absence of a specific adapter, we just want to keep everything stationary.
a = new AlphaAnimation(1.f, 1.f);
a.setDuration(WindowChangeAnimationSpec.ANIMATION_DURATION);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
a, appTransitionToString(transit), enter, Debug.getCallers(3));
} else {
/* 见 frameworks/base/core/res/res/values/styles.xml
*/
int animAttr = 0;
switch (transit) {
case TRANSIT_ACTIVITY_OPEN:
case TRANSIT_TRANSLUCENT_ACTIVITY_OPEN:
animAttr = enter
? WindowAnimation_activityOpenEnterAnimation
: WindowAnimation_activityOpenExitAnimation;
break;
case TRANSIT_ACTIVITY_CLOSE:
case TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE:
animAttr = enter
? WindowAnimation_activityCloseEnterAnimation
: WindowAnimation_activityCloseExitAnimation;
break;
case TRANSIT_DOCK_TASK_FROM_RECENTS:
case TRANSIT_TASK_OPEN:
animAttr = enter
? WindowAnimation_taskOpenEnterAnimation
: WindowAnimation_taskOpenExitAnimation;
break;
case TRANSIT_TASK_CLOSE:
animAttr = enter
? WindowAnimation_taskCloseEnterAnimation
: WindowAnimation_taskCloseExitAnimation;
break;
case TRANSIT_TASK_TO_FRONT:
animAttr = enter
? WindowAnimation_taskToFrontEnterAnimation
: WindowAnimation_taskToFrontExitAnimation;
break;
case TRANSIT_TASK_TO_BACK:
animAttr = enter
? WindowAnimation_taskToBackEnterAnimation
: WindowAnimation_taskToBackExitAnimation;
break;
case TRANSIT_WALLPAPER_OPEN:
animAttr = enter
? WindowAnimation_wallpaperOpenEnterAnimation
: WindowAnimation_wallpaperOpenExitAnimation;
break;
case TRANSIT_WALLPAPER_CLOSE:
animAttr = enter
? WindowAnimation_wallpaperCloseEnterAnimation
: WindowAnimation_wallpaperCloseExitAnimation;
break;
case TRANSIT_WALLPAPER_INTRA_OPEN:
animAttr = enter
? WindowAnimation_wallpaperIntraOpenEnterAnimation
: WindowAnimation_wallpaperIntraOpenExitAnimation;
break;
case TRANSIT_WALLPAPER_INTRA_CLOSE:
animAttr = enter
? WindowAnimation_wallpaperIntraCloseEnterAnimation
: WindowAnimation_wallpaperIntraCloseExitAnimation;
break;
case TRANSIT_TASK_OPEN_BEHIND:
animAttr = enter
? WindowAnimation_launchTaskBehindSourceAnimation
: WindowAnimation_launchTaskBehindTargetAnimation;
}
a = animAttr != 0 ? loadAnimationAttr(lp, animAttr, transit) : null;
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "
+ "Callers=%s",
a, animAttr, appTransitionToString(transit), enter,
Debug.getCallers(3));
}
return a;
}
Animation loadAnimationAttr(LayoutParams lp, int animAttr, int transit) {
int resId = Resources.ID_NULL;
Context context = mContext;
/*依照包名从应用中获取过渡动画
*/
if (animAttr >= 0) {
AttributeCache.Entry ent = getCachedAnimations(lp);
if (ent != null) {
context = ent.context;
resId = ent.array.getResourceId(animAttr, 0);
}
}
/*对透明Activity做特殊处理
*/
resId = updateToTranslucentAnimIfNeeded(resId, transit);
/*加载过渡动画
*/
if (ResourceId.isValid(resId)) {
return loadAnimationSafely(context, resId);
}
return null;
}
注:系统内置动画frameworks/base/core/res/res/values/styles.xml
<!-- Standard animations for a full-screen window or activity. -->
<style name="Animation.Activity">
<item name="activityOpenEnterAnimation">@anim/activity_open_enter</item>
<item name="activityOpenExitAnimation">@anim/activity_open_exit</item>
<item name="activityCloseEnterAnimation">@anim/activity_close_enter</item>
<item name="activityCloseExitAnimation">@anim/activity_close_exit</item>
<item name="taskOpenEnterAnimation">@anim/task_open_enter</item>
<item name="taskOpenExitAnimation">@anim/task_open_exit</item>
<item name="launchTaskBehindTargetAnimation">@anim/launch_task_behind_target</item>
<item name="launchTaskBehindSourceAnimation">@anim/launch_task_behind_source</item>
<item name="taskCloseEnterAnimation">@anim/task_close_enter</item>
<item name="taskCloseExitAnimation">@anim/task_close_exit</item>
<item name="taskToFrontEnterAnimation">@anim/task_open_enter</item>
<item name="taskToFrontExitAnimation">@anim/task_open_exit</item>
<item name="taskToBackEnterAnimation">@anim/task_close_enter</item>
<item name="taskToBackExitAnimation">@anim/task_close_exit</item>
<item name="wallpaperOpenEnterAnimation">@anim/wallpaper_open_enter</item>
<item name="wallpaperOpenExitAnimation">@anim/wallpaper_open_exit</item>
<item name="wallpaperCloseEnterAnimation">@anim/wallpaper_close_enter</item>
<item name="wallpaperCloseExitAnimation">@anim/wallpaper_close_exit</item>
<item name="wallpaperIntraOpenEnterAnimation">@anim/wallpaper_intra_open_enter</item>
<item name="wallpaperIntraOpenExitAnimation">@anim/wallpaper_intra_open_exit</item>
<item name="wallpaperIntraCloseEnterAnimation">@anim/wallpaper_intra_close_enter</item>
<item name="wallpaperIntraCloseExitAnimation">@anim/wallpaper_intra_close_exit</item>
<item name="fragmentOpenEnterAnimation">@animator/fragment_open_enter</item>
<item name="fragmentOpenExitAnimation">@animator/fragment_open_exit</item>
<item name="fragmentCloseEnterAnimation">@animator/fragment_close_enter</item>
<item name="fragmentCloseExitAnimation">@animator/fragment_close_exit</item>
<item name="fragmentFadeEnterAnimation">@animator/fragment_fade_enter</item>
<item name="fragmentFadeExitAnimation">@animator/fragment_fade_exit</item>
</style>
五.总结:
AppTransition是系统窗口动画的重要部分,是启动应用,退出应用,切换Activity的过渡动画的管理者。AppTransition不仅支持系统的过渡动画,也可以通过定制style或者Actiivty中overridePendingTransition的方式设置过渡动画,而且也支持远程动画(如Launcher3设置RemoteAnimationController)。AppTransition会把需要的动画交给SurfaceAnimationRunner作处理,而SurfaceAnimationRunner则通过Choreographer在vsync下一帧到来时启动过渡动画。
过渡动画过程为:
(1)AppTransition.prepareAppTransitionLocked 确定基础的过渡动画类型
(2)DisplayContent.executeAppTransition 申请执行过渡动画
(3)WindowSurfacePlacer.performSurfacePlacement 获取过渡动画实例,添加至系统动画系统
RootWindowContainer.checkAppTransitionReady
AppTransitionController.handleAppTransitionReady
AppTransitionController.applyAnimations
WindowContainer.applyAnimation
WindowContainer.applyAnimationUnchecked
WindowContainer.getAnimationAdapter
AppTransition.loadAnimation
WindowContainer.startAnimation
SurfaceAnimator.startAnimation
LocalAnimationAdapter.startAnimation
SurfaceAnimationRunner.startAnimation
(4)SurfaceAnimationRunner.startPendingAnimationsLocked 通过Choreographer.postFrameCallback调用,开启动画