AOSP 14 Activity 默认关闭动画详细代码流程分析
概述
本文档详细分析在未开启 Shell Transition的情况下,AOSP 14 中 Activity 默认关闭动画的完整设置和加载流程。
一、完整调用链概览
[App 进程]
Activity.finish()
│
▼
Activity.finish(int finishTask) [Activity.java:7018]
│
▼
ActivityClient.finishActivity() [ActivityClient.java:172]
│ (Binder IPC)
▼
[System Server 进程]
ActivityClientController.finishActivity() [ActivityClientController.java:424]
│
▼
ActivityRecord.finishIfPossible(int, Intent, NeededUriGrants, String, boolean) [ActivityRecord.java:3496]
│
├─► DisplayContent.prepareAppTransition(TRANSIT_CLOSE) [ActivityRecord.java:3568]
│ │
│ ▼
│ DisplayContent.prepareAppTransition(int, int) [DisplayContent.java:5608]
│ │
│ ▼
│ AppTransition.prepareAppTransition(int, int) [AppTransition.java:1480]
│
├─► ActivityRecord.setVisibility(false) [ActivityRecord.java:3584]
│ │
│ ▼
│ ActivityRecord.setVisibility(boolean, boolean) [ActivityRecord.java:5307]
│ │
│ ▼
│ ActivityRecord.deferCommitVisibilityChange(false) [ActivityRecord.java:5455]
│ │
│ ▼
│ DisplayContent.mClosingApps.add(this) [ActivityRecord.java:5497]
│
▼
AppTransitionController.handleAppTransitionReady() [AppTransitionController.java:172]
│
├─► AppTransitionController.transitionGoodToGo() [AppTransitionController.java:174]
│
├─► AppTransitionController.getTransitCompatType() [AppTransitionController.java:263]
│ │
│ ▼
│ AppTransitionController.getAnimationTargets() [AppTransitionController.java:475-476]
│ │
│ ▼
│ AppTransitionController.getTransitContainerType() [AppTransitionController.java:547]
│ 返回 TRANSIT_OLD_ACTIVITY_CLOSE [AppTransitionController.java:530]
│
├─► AppTransitionController.findAnimLayoutParamsToken() [AppTransitionController.java:279]
│ │
│ ▼
│ AppTransitionController.getAnimLp() [AppTransitionController.java:560]
│
├─► AppTransitionController.applyAnimations(ArraySet<ActivityRecord>, ...) [AppTransitionController.java:300]
│ │
│ ▼
│ AppTransitionController.getAnimationTargets() [AppTransitionController.java:1107-1109]
│ │
│ ▼
│ AppTransitionController.applyAnimations(ArraySet<WindowContainer>, ...) [AppTransitionController.java:909]
│ │
│ ▼
│ WindowContainer.applyAnimation(LayoutParams, int, boolean, boolean, ArrayList) [WindowContainer.java:3092]
│ │
│ ▼
│ WindowContainer.applyAnimationUnchecked(LayoutParams, boolean, int, boolean, ArrayList) [WindowContainer.java:3253]
│ │
│ ▼
│ WindowContainer.getAnimationAdapter(LayoutParams, int, boolean, boolean) [WindowContainer.java:3097]
│ │
│ ▼
│ WindowContainer.loadAnimation(LayoutParams, int, boolean, boolean) [WindowContainer.java:3355]
│ │
│ ▼
│ AppTransition.loadAnimation(LayoutParams, int, boolean, int, int, Rect, ...) [AppTransition.java:764]
│ │
│ ├─► AppTransition.mapOpenCloseTransitTypes(int, boolean) [AppTransition.java:892]
│ │ 返回 activityCloseExitAnimation [AppTransition.java:565-566]
│ │
│ └─► TransitionAnimation.loadDefaultAnimationAttr(int, int) [AppTransition.java:897]
│ │
│ ▼
│ TransitionAnimation.loadAnimationAttr(String, int, int, boolean, int) [TransitionAnimation.java:348]
│
├─► AppTransitionController.handleClosingApps() [AppTransitionController.java:302]
│ │
│ ▼
│ ActivityRecord.commitVisibility(false, boolean) [AppTransitionController.java:1208]
│ │
│ ▼
│ ActivityRecord.updateReportedVisibilityLocked() [AppTransitionController.java:1209]
│
├─► AppTransitionController.handleOpeningApps() [AppTransitionController.java:303]
│ │
│ ▼
│ ActivityRecord.commitVisibility(true, boolean) [AppTransitionController.java:1163]
│ │
│ ▼
│ ActivityRecord.showAllWindowsLocked() [AppTransitionController.java:1180]
│
└─► AppTransitionController.handleChangingApps(int) [AppTransitionController.java:304]
二、详细代码分析(逐步跟踪)
步骤 1: App 进程发起 finish 请求
1.1 Activity.finish()
文件: frameworks/base/core/java/android/app/Activity.java
// 第 7018-7020 行
public void finish() {
finish(DONT_FINISH_TASK_WITH_ACTIVITY);
}
说明: 用户调用 Activity.finish() 方法,内部调用重载方法 finish(int finishTask),参数 DONT_FINISH_TASK_WITH_ACTIVITY 表示只 finish 当前 Activity,不 finish 整个 Task。
1.2 Activity.finish(int finishTask)
文件: frameworks/base/core/java/android/app/Activity.java
// 第 6990-7008 行
private void finish(int finishTask) {
if (mParent == null) {
int resultCode;
Intent resultData;
synchronized (this) {
resultCode = mResultCode;
resultData = mResultData;
}
if (false) Log.v(TAG, "Finishing self: token=" + mToken);
if (resultData != null) {
resultData.prepareToLeaveProcess(this);
}
// 关键调用:通过 ActivityClient 发起 finish 请求
if (ActivityClient.getInstance().finishActivity(mToken, resultCode, resultData,
finishTask)) {
mFinished = true;
}
} else {
mParent.finishFromChild(this);
}
getAutofillClientController().onActivityFinish(mIntent);
}
说明: 此方法收集 Activity 的结果码和结果数据,然后通过 ActivityClient.getInstance().finishActivity() 发起 Binder IPC 调用到 System Server。
1.3 ActivityClient.finishActivity()
文件: frameworks/base/core/java/android/app/ActivityClient.java
// 第 172-179 行
public boolean finishActivity(IBinder token, int resultCode, Intent resultData,
int finishTask) {
try {
// 关键调用:通过 Binder 调用 ActivityClientController 的 finishActivity 方法
return getActivityClientController().finishActivity(token, resultCode, resultData,
finishTask);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
说明: ActivityClient 是 App 进程与 System Server 通信的客户端代理,通过 getActivityClientController() 获取 IActivityClientController 的 Binder 代理,发起跨进程调用。
步骤 2: System Server 处理 finish 请求
2.1 ActivityClientController.finishActivity()
文件: frameworks/base/services/core/java/com/android/server/wm/ActivityClientController.java
// 第 424-509 行
@Override
public boolean finishActivity(IBinder token, int resultCode, Intent resultData,
int finishTask) {
// Refuse possible leaked file descriptors.
if (resultData != null && resultData.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
final ActivityRecord r;
synchronized (mGlobalLock) {
// 根据 token 查找对应的 ActivityRecord
r = ActivityRecord.isInRootTaskLocked(token);
if (r == null) {
return true;
}
}
// Carefully collect grants without holding lock.
final NeededUriGrants resultGrants = mService.collectGrants(resultData, r.resultTo);
synchronized (mGlobalLock) {
// Check again in case activity was removed when collecting grants.
if (!r.isInHistory()) {
return true;
}
// Keep track of the root activity of the task before we finish it.
final Task tr = r.getTask();
final ActivityRecord rootR = tr.getRootActivity();
if (rootR == null) {
Slog.w(TAG, "Finishing task with all activities already finished");
}
// Do not allow task to finish if last task in lockTask mode. Launchable priv-apps can
// finish.
if (mService.getLockTaskController().activityBlockedFromFinish(r)) {
return false;
}
// ... 省略部分代码 ...
final long origId = Binder.clearCallingIdentity();
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "finishActivity");
try {
final boolean res;
final boolean finishWithRootActivity =
finishTask == Activity.FINISH_TASK_WITH_ROOT_ACTIVITY;
if (finishTask == Activity.FINISH_TASK_WITH_ACTIVITY
|| (finishWithRootActivity && r == rootR)) {
// ... 处理 finish task 的情况 ...
} else {
// 关键调用:调用 ActivityRecord.finishIfPossible
r.finishIfPossible(resultCode, resultData, resultGrants, "app-request",
true /* oomAdj */);
res = r.finishing;
if (!res) {
Slog.i(TAG, "Failed to finish by app-request");
}
}
return res;
} finally {
Trace.traceEnd(Trace.TAG_WINDOW_MANAGER);
Binder.restoreCallingIdentity(origId);
}
}
}
说明:
- 此方法在 System Server 进程中执行
- 通过
ActivityRecord.isInRootTaskLocked(token)根据 token 查找对应的ActivityRecord - 最终调用
r.finishIfPossible()方法处理 finish 逻辑
步骤 3: ActivityRecord.finishIfPossible() 准备关闭过渡
3.1 finishIfPossible 方法入口
文件: frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
// 第 3496-3520 行
@FinishRequest int finishIfPossible(int resultCode, Intent resultData,
NeededUriGrants resultGrants, String reason, boolean oomAdj) {
ProtoLog.v(WM_DEBUG_STATES, "Finishing activity r=%s, result=%d, data=%s, "
+ "reason=%s", this, resultCode, resultData, reason);
if (finishing) {
Slog.w(TAG, "Duplicate finish request for r=" + this);
return FINISH_RESULT_CANCELLED;
}
if (!isInRootTaskLocked()) {
Slog.w(TAG, "Finish request when not in root task for r=" + this);
return FINISH_RESULT_CANCELLED;
}
final Task rootTask = getRootTask();
final boolean mayAdjustTop = (isState(RESUMED) || rootTask.getTopResumedActivity() == null)
&& rootTask.isFocusedRootTaskOnDisplay()
&& !task.isClearingToReuseTask();
final boolean shouldAdjustGlobalFocus = mayAdjustTop
&& mRootWindowContainer.isTopDisplayFocusedRootTask(rootTask);
mAtmService.deferWindowLayout();
try {
mTaskSupervisor.mNoHistoryActivities.remove(this);
makeFinishingLocked(); // 标记 Activity 为 finishing 状态
// ... 继续执行 ...
说明:
- 方法首先检查是否已经是 finishing 状态,避免重复 finish
- 调用
makeFinishingLocked()将 Activity 标记为 finishing 状态 - 调用
mAtmService.deferWindowLayout()延迟窗口布局
3.2 准备关闭过渡动画
文件: frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
// 第 3550-3590 行
// ... 前面的代码 ...
finishActivityResults(resultCode, resultData, resultGrants);
final boolean endTask = task.getTopNonFinishingActivity() == null
&& !task.isClearingToReuseTask();
// 请求关闭过渡(用于 Shell Transition,如果未启用则返回 null)
final Transition newTransition =
mTransitionController.requestCloseTransitionIfNeeded(endTask ? task : this);
if (isState(RESUMED)) {
if (endTask) {
mAtmService.getTaskChangeNotificationController().notifyTaskRemovalStarted(
task.getTaskInfo());
}
// Prepare app close transition, but don't execute just yet. It is possible that
// an activity that will be made resumed in place of this one will immediately
// launch another new activity. In this case current closing transition will be
// combined with open transition for the new activity.
if (DEBUG_VISIBILITY || DEBUG_TRANSITION) {
Slog.v(TAG_TRANSITION, "Prepare close transition: finishing " + this);
}
// ★★★ 关键调用:声明关闭过渡类型 ★★★
mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
// When finishing the activity preemptively take the snapshot before the app window
// is marked as hidden and any configuration changes take place
// Note that RecentsAnimation will handle task snapshot while switching apps with
// the best capture timing (e.g. IME window capture),
// No need additional task capture while task is controlled by RecentsAnimation.
if (!mTransitionController.isShellTransitionsEnabled()
&& !task.isAnimatingByRecents()) {
final ArraySet<Task> tasks = Sets.newArraySet(task);
mAtmService.mWindowManager.mTaskSnapshotController.snapshotTasks(tasks);
mAtmService.mWindowManager.mTaskSnapshotController
.addSkipClosingAppSnapshotTasks(tasks);
}
// Tell window manager to prepare for this one to be removed.
// ★★★ 关键调用:设置 Activity 不可见 ★★★
setVisibility(false);
说明:
- 第 3568 行:
mDisplayContent.prepareAppTransition(TRANSIT_CLOSE)- 声明关闭过渡类型 - 第 3584 行:
setVisibility(false)- 设置 Activity 不可见,这会将 Activity 加入到mClosingApps列表
步骤 4: prepareAppTransition 声明关闭过渡
4.1 DisplayContent.prepareAppTransition(int)
文件: frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
// 第 5608-5613 行
void prepareAppTransition(@WindowManager.TransitionType int transit) {
prepareAppTransition(transit, 0 /* flags */);
}
说明: 重载方法,调用带有 flags 参数的版本。
4.2 DisplayContent.prepareAppTransition(int, int)
文件: frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
// 第 5615-5621 行
void prepareAppTransition(@WindowManager.TransitionType int transit,
@WindowManager.TransitionFlags int flags) {
final boolean prepared = mAppTransition.prepareAppTransition(transit, flags);
if (prepared && okToAnimate() && transit != TRANSIT_NONE) {
mSkipAppTransitionAnimation = false;
}
}
说明: 调用 AppTransition.prepareAppTransition() 方法。
4.3 AppTransition.prepareAppTransition(int, int)
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransition.java
// 第 1480-1494 行
boolean prepareAppTransition(@TransitionType int transit, @TransitionFlags int flags) {
if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) {
return false; // 如果启用了 Shell Transition,直接返回
}
// ★★★ 关键:将 TRANSIT_CLOSE 添加到请求列表 ★★★
mNextAppTransitionRequests.add(transit);
mNextAppTransitionFlags |= flags;
updateBooster();
removeAppTransitionTimeoutCallbacks();
mHandler.postDelayed(mHandleAppTransitionTimeoutRunnable,
APP_TRANSITION_TIMEOUT_MS);
return prepare();
}
说明:
- 检查是否启用了 Shell Transition,如果启用则直接返回 false
- 将过渡类型
TRANSIT_CLOSE添加到mNextAppTransitionRequests列表中 - 设置超时回调,防止过渡动画无限等待
步骤 5: setVisibility(false) 将 Activity 加入关闭列表
5.1 ActivityRecord.setVisibility(boolean)
文件: frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
// 第 5289-5305 行
void setVisibility(boolean visible) {
if (getParent() == null) {
Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token);
return;
}
if (visible == mVisibleRequested && visible == mVisible && visible == isClientVisible()
&& mTransitionController.isShellTransitionsEnabled()) {
// For shell transition, it is no-op if there is no state change.
return;
}
if (visible) {
mDeferHidingClient = false;
}
// 调用内部方法
setVisibility(visible, mDeferHidingClient);
mAtmService.addWindowLayoutReasons(
ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED);
mTaskSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this);
mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
}
说明: setVisibility(boolean visible) 调用内部重载方法 setVisibility(boolean visible, boolean deferHidingClient)。
5.2 ActivityRecord.setVisibility(boolean, boolean)
文件: frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
// 第 5307-5455 行
private void setVisibility(boolean visible, boolean deferHidingClient) {
final AppTransition appTransition = getDisplayContent().mAppTransition;
// Don't set visibility to false if we were already not visible. This prevents WM from
// adding the app to the closing app list which doesn't make sense for something that is
// already not visible.
if (!visible && !mVisibleRequested) {
// ... 省略部分代码 ...
return;
}
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",
token, visible, appTransition, isVisible(), mVisibleRequested,
Debug.getCallers(6));
// ... 省略中间代码 ...
// 从 openingApps 和 closingApps 中移除自己(避免重复)
displayContent.mOpeningApps.remove(this);
displayContent.mClosingApps.remove(this);
waitingToShow = false;
setVisibleRequested(visible);
mLastDeferHidingClient = deferHidingClient;
// ... 省略中间代码 ...
// 如果正在收集过渡动画,延迟提交可见性变化
if (isCollecting) {
return;
}
if (inFinishingTransition) {
mTransitionController.mValidateCommitVis.add(this);
return;
}
// ★★★ 关键调用:延迟提交可见性变化 ★★★
if (deferCommitVisibilityChange(visible)) {
return;
}
commitVisibility(visible, true /* performLayout */);
updateReportedVisibilityLocked();
}
说明:
- 先从
mOpeningApps和mClosingApps中移除自己,避免重复 - 调用
deferCommitVisibilityChange(visible)决定是否延迟提交可见性变化
5.3 ActivityRecord.deferCommitVisibilityChange(boolean)
文件: frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
// 第 5457-5510 行
private boolean deferCommitVisibilityChange(boolean visible) {
if (mTransitionController.isShellTransitionsEnabled()) {
// Shell transition doesn't use opening/closing sets.
return false;
}
if (!mDisplayContent.mAppTransition.isTransitionSet()) {
// Defer committing visibility for non-home app which is animating by recents.
if (isActivityTypeHome() || !isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) {
return false;
}
}
if (mWaitForEnteringPinnedMode && mVisible == visible) {
return false;
}
// The animation will be visible soon so do not skip by screen off.
final boolean ignoreScreenOn = canTurnScreenOn() || mTaskSupervisor.getKeyguardController()
.isKeyguardGoingAway(mDisplayContent.mDisplayId);
// Ignore display frozen so the opening / closing transition type can be updated correctly
// even if the display is frozen.
if (!okToAnimate(true /* ignoreFrozen */, ignoreScreenOn)) {
return false;
}
// ★★★ 关键:根据 visible 决定加入 openingApps 还是 closingApps ★★★
if (visible) {
// 如果是要变为可见,加入 openingApps
mDisplayContent.mOpeningApps.add(this);
mEnteringAnimation = true;
} else if (mVisible) {
// ★★★ 如果是要变为不可见且当前可见,加入 closingApps ★★★
mDisplayContent.mClosingApps.add(this);
mEnteringAnimation = false;
}
// ... 省略部分代码 ...
return true;
}
说明:
- 第 5495-5497 行: 这是关键代码,当
visible=false且当前mVisible=true时,将 Activity 加入到mClosingApps列表 - 此方法返回
true,表示延迟提交可见性变化,等待过渡动画开始后再提交
步骤 6: 过渡动画触发时机
当 Activity 设置为不可见后,系统会等待过渡动画准备好,然后调用 handleAppTransitionReady()。
过渡动画触发的时机有两种情况:
- RESUMED 状态的 Activity finish: 会触发
startPausing(),等待 pause 完成后触发过渡 - 非 RESUMED 状态的 Activity finish: 会调用
prepareActivityHideTransitionAnimation()直接执行过渡
6.1 ActivityRecord.prepareActivityHideTransitionAnimation()
文件: frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
// 第 3667-3672 行
private void prepareActivityHideTransitionAnimation() {
final DisplayContent dc = mDisplayContent;
dc.prepareAppTransition(TRANSIT_CLOSE); // 声明关闭过渡
setVisibility(false); // 设置不可见
dc.executeAppTransition(); // 立即执行过渡
}
6.2 DisplayContent.executeAppTransition()
文件: frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
// 第 5634-5643 行
void executeAppTransition() {
mTransitionController.setReady(this);
if (mAppTransition.isTransitionSet()) {
ProtoLog.w(WM_DEBUG_APP_TRANSITIONS,
"Execute app transition: %s, displayId: %d Callers=%s",
mAppTransition, mDisplayId, Debug.getCallers(5));
mAppTransition.setReady();
mWmService.mWindowPlacerLocked.requestTraversal();
}
}
说明: 调用 mAppTransition.setReady() 标记过渡准备完成,然后请求布局遍历,这会触发 handleAppTransitionReady()。
步骤 7: AppTransitionController.handleAppTransitionReady() 处理过渡
7.1 handleAppTransitionReady() 方法入口
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 172-180 行
void handleAppTransitionReady() {
mTempTransitionReasons.clear();
// ★★★ 关键调用:检查所有打开的 App 是否准备好 ★★★
if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
|| !transitionGoodToGo(mDisplayContent.mChangingContainers, mTempTransitionReasons)
|| !transitionGoodToGoForTaskFragments()) {
return; // 如果没准备好,等待下次调用
}
// ... 省略部分代码 ...
说明: 首先调用 transitionGoodToGo() 检查所有参与过渡的 App 是否准备好。
7.2 AppTransitionController.transitionGoodToGo()
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 1287-1380 行
private boolean transitionGoodToGo(ArraySet<? extends WindowContainer> apps,
ArrayMap<WindowContainer, Integer> outReasons) {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"Checking %d opening apps (frozen=%b timeout=%b)...", apps.size(),
mService.mDisplayFrozen, mDisplayContent.mAppTransition.isTimeout());
if (mDisplayContent.mAppTransition.isTimeout()) {
return true; // 超时则直接开始
}
// ... 检查屏幕旋转动画 ...
for (int i = 0; i < apps.size(); i++) {
WindowContainer wc = apps.valueAt(i);
// ... 检查每个窗口是否准备好 ...
}
return true;
}
说明: 检查所有参与过渡的窗口容器是否准备好。
7.3 清理动画标志和调整壁纸
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 218-250 行
// ... 前面的代码 ...
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "**** GOOD TO GO");
// 清理动画退出状态的窗口
mDisplayContent.forAllWindows(WindowState::cleanupAnimatingExitWindow,
true /* traverseTopToBottom */);
final AppTransition appTransition = mDisplayContent.mAppTransition;
mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
appTransition.removeAppTransitionTimeoutCallbacks();
mDisplayContent.mWallpaperMayChange = false;
int appCount = mDisplayContent.mOpeningApps.size();
for (int i = 0; i < appCount; ++i) {
// 清除 openingApps 的动画标志
mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
}
appCount = mDisplayContent.mChangingContainers.size();
for (int i = 0; i < appCount; ++i) {
final ActivityRecord activity = getAppFromContainer(
mDisplayContent.mChangingContainers.valueAtUnchecked(i));
if (activity != null) {
activity.clearAnimatingFlags();
}
}
// 调整壁纸窗口
mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
mDisplayContent.mOpeningApps);
说明:
- 调用
WindowState.cleanupAnimatingExitWindow()清理动画退出状态的窗口 - 调用
clearAnimatingFlags()清除动画标志 - 调用
adjustWallpaperWindowsForAppTransitionIfNeeded()调整壁纸窗口
步骤 8: 确定过渡类型
8.1 获取过渡类型
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 252-275 行
ArraySet<ActivityRecord> tmpOpenApps = mDisplayContent.mOpeningApps;
ArraySet<ActivityRecord> tmpCloseApps = mDisplayContent.mClosingApps;
if (mDisplayContent.mAtmService.mBackNavigationController.isMonitoringTransition()) {
tmpOpenApps = new ArraySet<>(mDisplayContent.mOpeningApps);
tmpCloseApps = new ArraySet<>(mDisplayContent.mClosingApps);
if (mDisplayContent.mAtmService.mBackNavigationController
.removeIfContainsBackAnimationTargets(tmpOpenApps, tmpCloseApps)) {
mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations();
}
}
// ★★★ 关键调用:确定过渡类型 ★★★
@TransitionOldType final int transit = getTransitCompatType(
mDisplayContent.mAppTransition, tmpOpenApps,
tmpCloseApps, mDisplayContent.mChangingContainers,
mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
mDisplayContent.mSkipAppTransitionAnimation);
mDisplayContent.mSkipAppTransitionAnimation = false;
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"handleAppTransitionReady: displayId=%d appTransition={%s}"
+ " openingApps=[%s] closingApps=[%s] transit=%s",
mDisplayContent.mDisplayId, appTransition.toString(), tmpOpenApps,
tmpCloseApps, AppTransition.appTransitionOldToString(transit));
说明: 调用 getTransitCompatType() 方法确定具体的过渡类型。
8.2 AppTransitionController.getTransitCompatType()
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 360-545 行
@TransitionOldType static int getTransitCompatType(AppTransition appTransition,
ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps,
ArraySet<WindowContainer> changingContainers, @Nullable WindowState wallpaperTarget,
@Nullable WindowState oldWallpaper, boolean skipAppTransitionAnimation) {
final ActivityRecord topOpeningApp = getTopApp(openingApps, false /* ignoreHidden */);
final ActivityRecord topClosingApp = getTopApp(closingApps, true /* ignoreHidden */);
// ... 省略 keyguard 和 dream 类型的处理 ...
@TransitionFlags final int flags = appTransition.getTransitFlags();
@TransitionType final int firstTransit = appTransition.getFirstAppTransition();
// ... 省略特殊过渡类型的处理 ...
// ★★★ 关键调用:获取动画目标容器 ★★★
final ArraySet<WindowContainer> openingWcs = getAnimationTargets(
openingApps, closingApps, true /* visible */);
final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
openingApps, closingApps, false /* visible */);
final WindowContainer<?> openingContainer = !openingWcs.isEmpty()
? openingWcs.valueAt(0) : null;
final WindowContainer<?> closingContainer = !closingWcs.isEmpty()
? closingWcs.valueAt(0) : null;
// ★★★ 关键调用:获取容器类型 ★★★
@TransitContainerType int openingType = getTransitContainerType(openingContainer);
@TransitContainerType int closingType = getTransitContainerType(closingContainer);
// ... 省略 TRANSIT_TO_FRONT 和 TRANSIT_TO_BACK 的处理 ...
if (appTransition.containsTransitRequest(TRANSIT_OPEN)) {
// ... 处理打开过渡 ...
}
// ★★★ 关键:处理关闭过渡 ★★★
if (appTransition.containsTransitRequest(TRANSIT_CLOSE)) {
if (closingType == TYPE_TASK) {
return TRANSIT_OLD_TASK_CLOSE; // Task 关闭
}
if (closingType == TYPE_TASK_FRAGMENT) {
return TRANSIT_OLD_TASK_FRAGMENT_CLOSE; // TaskFragment 关闭
}
if (closingType == TYPE_ACTIVITY) {
// 遍历 closingApps,检查是否有可见的 Activity
for (int i = closingApps.size() - 1; i >= 0; i--) {
if (closingApps.valueAt(i).visibleIgnoringKeyguard) {
// ★★★ 返回 Activity 关闭过渡类型 ★★★
return TRANSIT_OLD_ACTIVITY_CLOSE;
}
}
// 如果没有可见的关闭 App,跳过过渡动画
return WindowManager.TRANSIT_OLD_UNSET;
}
}
// ... 省略其他过渡类型 ...
return TRANSIT_OLD_NONE;
}
说明:
- 调用
getAnimationTargets()获取动画目标容器 - 调用
getTransitContainerType()获取容器类型(TYPE_ACTIVITY, TYPE_TASK, TYPE_TASK_FRAGMENT) - 对于 Activity 关闭,返回
TRANSIT_OLD_ACTIVITY_CLOSE
8.3 AppTransitionController.getAnimationTargets()
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 950-1070 行
private ArraySet<WindowContainer> getAnimationTargets(
ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps,
boolean visible) {
// 收集候选容器
final ArraySet<WindowContainer> candidates = new ArraySet<>();
final ArraySet<ActivityRecord> apps = visible ? openingApps : closingApps;
for (int i = 0; i < apps.size(); i++) {
final ActivityRecord app = apps.valueAt(i);
if (app.shouldApplyAnimation(visible)) {
candidates.add(app);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"Changing app %s visible=%b performLayout=%b",
app, app.isVisible(), false);
}
}
// ... 省略动画目标提升逻辑 ...
return targets;
}
说明: 获取需要应用动画的 WindowContainer 集合。
8.4 AppTransitionController.getTransitContainerType()
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 547-560 行
@TransitContainerType
private static int getTransitContainerType(@Nullable WindowContainer<?> container) {
if (container == null) {
return TYPE_NONE;
}
if (container.asTask() != null) {
return TYPE_TASK;
}
if (container.asTaskFragment() != null) {
return TYPE_TASK_FRAGMENT;
}
if (container.asActivityRecord() != null) {
return TYPE_ACTIVITY; // ★★★ Activity 类型 ★★★
}
return TYPE_NONE;
}
说明: 判断容器的类型,对于 ActivityRecord 返回 TYPE_ACTIVITY。
步骤 9: 获取动画布局参数
9.1 收集 Activity 类型
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 277-280 行
// Find the layout params of the top-most application window in the tokens, which is
// what will control the animation theme.
final ArraySet<Integer> activityTypes = collectActivityTypes(tmpOpenApps,
tmpCloseApps, mDisplayContent.mChangingContainers);
9.2 AppTransitionController.collectActivityTypes()
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 842-857 行
private static ArraySet<Integer> collectActivityTypes(ArraySet<ActivityRecord> array1,
ArraySet<ActivityRecord> array2, ArraySet<WindowContainer> array3) {
final ArraySet<Integer> result = new ArraySet<>();
for (int i = array1.size() - 1; i >= 0; i--) {
result.add(array1.valueAt(i).getActivityType());
}
for (int i = array2.size() - 1; i >= 0; i--) {
result.add(array2.valueAt(i).getActivityType());
}
for (int i = array3.size() - 1; i >= 0; i--) {
result.add(array3.valueAt(i).getActivityType());
}
return result;
}
9.3 AppTransitionController.findAnimLayoutParamsToken()
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 810-840 行
@Nullable
private ActivityRecord findAnimLayoutParamsToken(@TransitionOldType int transit,
ArraySet<Integer> activityTypes, ArraySet<ActivityRecord> openingApps,
ArraySet<ActivityRecord> closingApps, ArraySet<WindowContainer> changingApps) {
ActivityRecord result;
// Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
w -> w.getRemoteAnimationDefinition() != null
&& w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
if (result != null) {
return result;
}
// 查找全屏窗口
result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
w -> w.fillsParent() && w.findMainWindow() != null);
if (result != null) {
return result;
}
// 查找任何有主窗口的 Activity
return lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
w -> w.findMainWindow() != null);
}
说明: 找到用于控制动画主题的 Activity。
9.4 AppTransitionController.getAnimLp()
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 560-564 行
@Nullable
private static WindowManager.LayoutParams getAnimLp(ActivityRecord activity) {
final WindowState mainWindow = activity != null ? activity.findMainWindow() : null;
return mainWindow != null ? mainWindow.mAttrs : null;
}
说明: 获取 Activity 主窗口的 LayoutParams。
步骤 10: 应用动画
10.1 AppTransitionController.applyAnimations(ArraySet, ...)
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 1095-1145 行
private void applyAnimations(ArraySet<ActivityRecord> openingApps,
ArraySet<ActivityRecord> closingApps, @TransitionOldType int transit,
LayoutParams animLp, boolean voiceInteraction) {
final RecentsAnimationController rac = mService.getRecentsAnimationController();
if (transit == WindowManager.TRANSIT_OLD_UNSET
|| (openingApps.isEmpty() && closingApps.isEmpty())) {
if (rac != null) {
rac.sendTasksAppeared();
}
return;
}
// ... 省略 letterbox 动画处理 ...
// ★★★ 关键调用:获取打开动画目标 ★★★
final ArraySet<WindowContainer> openingWcs = getAnimationTargets(
openingApps, closingApps, true /* visible */);
// ★★★ 关键调用:获取关闭动画目标 ★★★
final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
openingApps, closingApps, false /* visible */);
// ★★★ 关键调用:为打开的 App 应用动画 ★★★
applyAnimations(openingWcs, openingApps, transit, true /* visible */, animLp,
voiceInteraction);
// ★★★ 关键调用:为关闭的 App 应用动画 ★★★
applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp,
voiceInteraction);
// ... 省略清理代码 ...
}
说明:
- 调用
getAnimationTargets()获取需要动画的 WindowContainer - 分别为打开和关闭的 App 调用
applyAnimations()
10.2 AppTransitionController.applyAnimations(ArraySet, ...)
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 909-927 行
private void applyAnimations(ArraySet<WindowContainer> wcs, ArraySet<ActivityRecord> apps,
@TransitionOldType 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);
// 收集参与过渡的 ActivityRecord
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);
}
}
// ★★★ 关键调用:为 WindowContainer 应用动画 ★★★
wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants);
}
}
说明: 遍历所有需要动画的 WindowContainer,调用其 applyAnimation() 方法。
步骤 11: WindowContainer.applyAnimation()
11.1 WindowContainer.applyAnimation(LayoutParams, int, boolean, boolean, ArrayList)
文件: frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
// 第 3092-3120 行
boolean applyAnimation(WindowManager.LayoutParams lp, @TransitionOldType 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;
}
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation");
if (okToAnimate()) {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: transit=%s, enter=%b, wc=%s",
AppTransition.appTransitionOldToString(transit), enter, this);
// ★★★ 关键调用:调用 applyAnimationUnchecked ★★★
applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
} else {
cancelAnimation();
}
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
return isAnimating();
}
说明:
- 检查是否禁用过渡动画
- 检查是否可以动画 (
okToAnimate()) - 调用
applyAnimationUnchecked()实际应用动画
11.2 WindowContainer.applyAnimationUnchecked()
文件: frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
// 第 3253-3280 行
protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
@TransitionOldType int transit, boolean isVoiceInteraction,
@Nullable ArrayList<WindowContainer> sources) {
final Task task = asTask();
if (task != null && !enter && !task.isActivityTypeHomeOrRecents()) {
// ... 处理 IME 截图 ...
}
// ★★★ 关键调用:获取动画适配器 ★★★
final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
transit, enter, isVoiceInteraction);
AnimationAdapter adapter = adapters.first;
AnimationAdapter thumbnailAdapter = adapters.second;
// ... 应用动画适配器 ...
}
说明: 调用 getAnimationAdapter() 获取动画适配器。
11.3 WindowContainer.getAnimationAdapter()
文件: frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
// 第 3097-3250 行
Pair<AnimationAdapter, AnimationAdapter> getAnimationAdapter(WindowManager.LayoutParams lp,
@TransitionOldType int transit, boolean enter, boolean isVoiceInteraction) {
// ... 省略远程动画处理 ...
// ★★★ 关键调用:加载本地动画 ★★★
mNeedsAnimationBoundsLayer = (appRootTaskClipMode == ROOT_TASK_CLIP_AFTER_ANIM);
final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
if (a != null) {
final float windowCornerRadius = !inMultiWindowMode()
? getDisplayContent().getWindowCornerRadius()
: 0;
// ... 省略部分代码 ...
// ★★★ 创建动画适配器 ★★★
AnimationAdapter adapter = new LocalAnimationAdapter(
new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
getDisplayContent().mAppTransition.canSkipFirstFrame(),
appRootTaskClipMode, true /* isAppAnimation */, windowCornerRadius),
getSurfaceAnimationRunner());
resultAdapters = new Pair<>(adapter, null);
mNeedsZBoost = a.getZAdjustment() == Animation.ZORDER_TOP
|| AppTransition.isClosingTransitOld(transit);
mTransit = transit;
mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
} else {
resultAdapters = new Pair<>(null, null);
}
return resultAdapters;
}
说明:
- 调用
loadAnimation()加载动画对象 - 创建
LocalAnimationAdapter包装动画 - 创建
WindowAnimationSpec包含动画规格
11.4 WindowContainer.loadAnimation()
文件: frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
// 第 3355-3410 行
private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
boolean isVoiceInteraction) {
if (AppTransitionController.isTaskViewTask(this) || (isOrganized()
&& getWindowingMode() != WINDOWING_MODE_FULLSCREEN
&& getWindowingMode() != WINDOWING_MODE_FREEFORM
&& getWindowingMode() != WINDOWING_MODE_MULTI_WINDOW)) {
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);
// 计算动画帧
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) {
enter = false;
}
ProtoLog.d(WM_DEBUG_APP_TRANSITIONS,
"Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s "
+ "surfaceInsets=%s",
AppTransition.appTransitionOldToString(transit), enter, frame, insets,
surfaceInsets);
final Configuration displayConfig = displayContent.getConfiguration();
// ★★★ 关键调用:通过 AppTransition 加载动画 ★★★
final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter,
displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets,
surfaceInsets, stableInsets, isVoiceInteraction, inFreeformWindowingMode(), this);
if (a != null) {
// 设置最大动画时长
a.restrictDuration(MAX_APP_TRANSITION_DURATION);
// ... 省略部分代码 ...
final int containingWidth = frame.width();
final int containingHeight = frame.height();
a.initialize(containingWidth, containingHeight, width, height);
a.scaleCurrentDuration(mWmService.getTransitionAnimationScaleLocked());
}
return a;
}
说明:
- 调用
getAnimationFrames()获取动画帧信息 - 调用
AppTransition.loadAnimation()加载动画对象
步骤 12: AppTransition.loadAnimation() 加载动画
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransition.java
// 第 764-920 行
@Nullable
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) {
final boolean canCustomizeAppTransition = container.canCustomizeAppTransition();
// ... 省略各种特殊过渡类型的处理 ...
// ★★★ 关键:默认动画加载路径 ★★★
} else {
// ★★★ 关键调用:映射过渡类型到动画属性 ★★★
int animAttr = mapOpenCloseTransitTypes(transit, enter);
if (animAttr != 0) {
final CustomAppTransition customAppTransition =
getCustomAppTransition(animAttr, container);
if (customAppTransition != null) {
a = loadCustomActivityAnimation(customAppTransition, enter, container);
} else {
if (canCustomizeAppTransition) {
a = loadAnimationAttr(lp, animAttr, transit);
} else {
// ★★★ 关键调用:加载默认动画 ★★★
a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr, transit);
}
}
} else {
a = null;
}
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "
+ " canCustomizeAppTransition=%b Callers=%s",
a, animAttr, AppTransition.appTransitionOldToString(transit), enter,
canCustomizeAppTransition, Debug.getCallers(3));
}
setAppTransitionFinishedCallbackIfNeeded(a);
return a;
}
说明:
- 调用
mapOpenCloseTransitTypes()将过渡类型映射到动画属性 - 调用
loadDefaultAnimationAttr()加载默认动画
步骤 13: AppTransition.mapOpenCloseTransitTypes() 映射动画属性
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransition.java
// 第 552-640 行
private static int mapOpenCloseTransitTypes(int transit, boolean enter) {
int animAttr = 0;
switch (transit) {
case TRANSIT_OLD_ACTIVITY_OPEN:
case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN:
animAttr = enter
? WindowAnimation_activityOpenEnterAnimation
: WindowAnimation_activityOpenExitAnimation;
break;
case TRANSIT_OLD_ACTIVITY_CLOSE:
case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE:
// ★★★ 关键:Activity 关闭的动画属性映射 ★★★
animAttr = enter
? WindowAnimation_activityCloseEnterAnimation // 下方 Activity 进入
: WindowAnimation_activityCloseExitAnimation; // 关闭 Activity 退出
break;
case TRANSIT_OLD_TASK_OPEN:
animAttr = enter
? WindowAnimation_taskOpenEnterAnimation
: WindowAnimation_taskOpenExitAnimation;
break;
case TRANSIT_OLD_TASK_CLOSE:
animAttr = enter
? WindowAnimation_taskCloseEnterAnimation
: WindowAnimation_taskCloseExitAnimation;
break;
// ... 其他过渡类型 ...
}
return animAttr;
}
说明:
- 对于
TRANSIT_OLD_ACTIVITY_CLOSE过渡类型:- 当
enter=true(下方露出的 Activity)时,返回WindowAnimation_activityCloseEnterAnimation - 当
enter=false(关闭的 Activity)时,返回WindowAnimation_activityCloseExitAnimation
- 当
步骤 14: TransitionAnimation.loadDefaultAnimationAttr() 加载默认动画
14.1 TransitionAnimation.loadDefaultAnimationAttr(int, int)
文件: frameworks/base/core/java/com/android/internal/policy/TransitionAnimation.java
// 第 350-353 行
/** Load animation by attribute Id from android package. */
@Nullable
public Animation loadDefaultAnimationAttr(int animAttr, @TransitionOldType int transit) {
return loadAnimationAttr(DEFAULT_PACKAGE, mDefaultWindowAnimationStyleResId, animAttr,
false /* translucent */, transit);
}
说明:
DEFAULT_PACKAGE = "android"- 表示从系统资源加载mDefaultWindowAnimationStyleResId- 系统主题中定义的windowAnimationStyle样式资源 ID
14.2 TransitionAnimation.loadAnimationAttr(String, int, int, boolean, int)
文件: frameworks/base/core/java/com/android/internal/policy/TransitionAnimation.java
// 第 348-360 行
@Nullable
public Animation loadAnimationAttr(String packageName, int animStyleResId, int animAttr,
boolean translucent, @TransitionOldType int transit) {
// 从 AttributeCache 获取动画样式
final AttributeCache.Entry ent = getCachedAnimations(packageName, animStyleResId);
if (ent != null) {
// 从样式中读取动画资源 ID
final int resId = ent.array.getResourceId(animAttr, 0);
if (resId != 0) {
// 加载动画资源
return loadAnimationSafely(mContext, resId, mTag);
}
}
return null;
}
说明:
- 调用
getCachedAnimations()从缓存中获取动画样式 - 从样式中读取动画资源 ID
- 调用
loadAnimationSafely()加载动画资源
步骤 15: AppTransitionController.handleClosingApps() 提交关闭可见性
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 1201-1225 行
private void handleClosingApps() {
final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
final int appsCount = closingApps.size();
for (int i = 0; i < appsCount; i++) {
final ActivityRecord app = closingApps.valueAt(i);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now closing app %s", app);
// ★★★ 关键调用:提交可见性变化为 false ★★★
app.commitVisibility(false /* visible */, false /* performLayout */);
// ★★★ 关键调用:更新报告的可见性 ★★★
app.updateReportedVisibilityLocked();
// 强制设置 allDrawn 标志,确保动画能启动
app.allDrawn = true;
// ★★★ 关键调用:移除 starting window ★★★
if (app.mStartingWindow != null && !app.mStartingWindow.mAnimatingExit) {
app.removeStartingWindow();
}
if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
app.attachThumbnailAnimation();
}
}
}
说明:
- 遍历
mClosingApps中的所有 Activity - 调用
commitVisibility(false, false)提交可见性变化 - 调用
updateReportedVisibilityLocked()更新报告的可见性 - 调用
removeStartingWindow()清理 starting window
步骤 16: AppTransitionController.handleOpeningApps() 提交打开可见性
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 1158-1200 行
private void handleOpeningApps() {
final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps;
final int appsCount = openingApps.size();
for (int i = 0; i < appsCount; i++) {
final ActivityRecord app = openingApps.valueAt(i);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", app);
// ★★★ 关键调用:提交可见性变化为 true ★★★
app.commitVisibility(true /* visible */, false /* performLayout */);
// ... 省略部分代码 ...
// ★★★ 关键调用:更新报告的可见性 ★★★
app.updateReportedVisibilityLocked();
app.waitingToShow = false;
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
">>> OPEN TRANSACTION handleAppTransitionReady()");
mService.openSurfaceTransaction();
try {
// ★★★ 关键调用:显示所有窗口 ★★★
app.showAllWindowsLocked();
} finally {
mService.closeSurfaceTransaction("handleAppTransitionReady");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
"<<< CLOSE TRANSACTION handleAppTransitionReady()");
}
if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) {
app.attachThumbnailAnimation();
} else if (mDisplayContent.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
app.attachCrossProfileAppsThumbnailAnimation();
}
}
}
说明:
- 遍历
mOpeningApps中的所有 Activity - 调用
commitVisibility(true, false)提交可见性变化 - 调用
showAllWindowsLocked()显示所有窗口
步骤 17: AppTransitionController.handleChangingApps() 处理变化的容器
文件: frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java
// 第 1245-1255 行
private void handleChangingApps(@TransitionOldType int transit) {
final ArraySet<WindowContainer> apps = mDisplayContent.mChangingContainers;
final int appsCount = apps.size();
for (int i = 0; i < appsCount; i++) {
WindowContainer wc = apps.valueAt(i);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", wc);
// ★★★ 关键调用:应用变化动画 ★★★
wc.applyAnimation(null, transit, true, false, null /* sources */);
}
}
三、默认关闭动画资源定义
3.1 动画样式定义
文件: frameworks/base/core-res/res/values/styles.xml
<!-- 第 96-130 行左右 -->
<style name="Animation.Activity">
<!-- Activity 打开动画 -->
<item name="activityOpenEnterAnimation">@anim/activity_open_enter</item>
<item name="activityOpenExitAnimation">@anim/activity_open_exit</item>
<!-- ★★★ Activity 关闭动画 ★★★ -->
<item name="activityCloseEnterAnimation">@anim/activity_close_enter</item>
<item name="activityCloseExitAnimation">@anim/activity_close_exit</item>
<!-- Task 打开/关闭动画 -->
<item name="taskOpenEnterAnimation">@anim/task_open_enter</item>
<item name="taskOpenExitAnimation">@anim/task_open_exit</item>
<item name="taskCloseEnterAnimation">@anim/task_close_enter</item>
<item name="taskCloseExitAnimation">@anim/task_close_exit</item>
<!-- 其他动画属性... -->
</style>
说明:
activityCloseEnterAnimation: 下方 Activity 进入动画(当顶部 Activity 关闭时)activityCloseExitAnimation: 关闭 Activity 的退出动画
3.2 关闭退出动画 (activity_close_exit.xml)
文件: frameworks/base/core-res/res/anim/activity_close_exit.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<!-- 透明度动画:从完全不透明渐变到完全透明 -->
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:startOffset="35"
android:duration="83"
android:interpolator="@interpolator/linear" />
<!-- 平移动画:向右平移 96dp -->
<translate
android:fromXDelta="0"
android:toXDelta="96dp"
android:duration="450"
android:interpolator="@interpolator/fast_out_extra_slow_in" />
<!-- 延伸动画:左侧延伸 96dp -->
<extend
android:fromExtendLeft="96dp"
android:toExtendLeft="0"
android:duration="450" />
</set>
动画效果:
- 透明度从 1.0 渐变到 0.0(先延迟 35ms,然后 83ms 完成)
- 同时向右平移 96dp(450ms 完成)
- 使用
fast_out_extra_slow_in插值器
3.3 关闭进入动画 (activity_close_enter.xml)
文件: frameworks/base/core-res/res/anim/activity_close_enter.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<!-- 透明度动画:保持完全不透明 -->
<alpha
android:fromAlpha="1.0"
android:toAlpha="1.0"
android:duration="450" />
<!-- 平移动画:从左侧 -96dp 平移到原位置 -->
<translate
android:fromXDelta="-96dp"
android:toXDelta="0"
android:duration="450"
android:interpolator="@interpolator/fast_out_extra_slow_in" />
<!-- 延伸动画:右侧延伸 96dp -->
<extend
android:fromExtendRight="96dp"
android:toExtendRight="0"
android:duration="450" />
</set>
动画效果:
- 透明度保持 1.0(完全不透明)
- 从左侧 -96dp 位置平移到原位置(450ms 完成)
- 使用
fast_out_extra_slow_in插值器
四、关键数据结构
4.1 Transition 类型常量
新版本 Transition 类型 (声明时使用):
| 常量 | 值 | 说明 |
|---|---|---|
TRANSIT_NONE | 0 | 无过渡 |
TRANSIT_OPEN | 1 | 打开 |
TRANSIT_CLOSE | 2 | 关闭 ← Activity 关闭使用 |
TRANSIT_TO_FRONT | 3 | 到前台 |
TRANSIT_TO_BACK | 4 | 到后台 |
TRANSIT_RELAUNCH | 5 | 重新启动 |
TRANSIT_CHANGE | 6 | 变更 |
旧版本 Transition 类型 (加载动画时使用):
| 常量 | 值 | 说明 |
|---|---|---|
TRANSIT_OLD_ACTIVITY_OPEN | 6 | Activity 打开 |
TRANSIT_OLD_ACTIVITY_CLOSE | 7 | Activity 关闭 ← 关闭动画匹配 |
TRANSIT_OLD_TASK_OPEN | 8 | Task 打开 |
TRANSIT_OLD_TASK_CLOSE | 9 | Task 关闭 |
TRANSIT_OLD_TASK_TO_FRONT | 10 | Task 到前台 |
TRANSIT_OLD_TASK_TO_BACK | 11 | Task 到后台 |
4.2 动画属性常量
定义在 com.android.internal.R.styleable.WindowAnimation:
| 常量 | 说明 |
|---|---|
activityOpenEnterAnimation | Activity 打开进入动画 |
activityOpenExitAnimation | Activity 打开退出动画 |
activityCloseEnterAnimation | Activity 关闭进入动画(下方 Activity) |
activityCloseExitAnimation | Activity 关闭退出动画(关闭的 Activity) |
taskOpenEnterAnimation | Task 打开进入动画 |
taskOpenExitAnimation | Task 打开退出动画 |
taskCloseEnterAnimation | Task 关闭进入动画 |
taskCloseExitAnimation | Task 关闭退出动画 |
五、关键代码位置总结表
| 步骤 | 文件 | 方法名 | 行号 | 作用 |
|---|---|---|---|---|
| 1 | Activity.java | finish() | 7018 | App 进程发起 finish 请求 |
| 2 | Activity.java | finish(int) | 7005 | 调用 ActivityClient |
| 3 | ActivityClient.java | finishActivity() | 172 | Binder IPC 调用 |
| 4 | ActivityClientController.java | finishActivity() | 424 | System Server 处理 finish |
| 5 | ActivityRecord.java | finishIfPossible(int, Intent, NeededUriGrants, String, boolean) | 3496 | 准备关闭过渡 |
| 6 | ActivityRecord.java | makeFinishingLocked() | 3526 | 标记为 finishing |
| 7 | DisplayContent.java | prepareAppTransition(int) | 5608 | 声明关闭过渡入口 |
| 8 | DisplayContent.java | prepareAppTransition(int, int) | 5615 | 调用 AppTransition |
| 9 | AppTransition.java | prepareAppTransition(int, int) | 1480 | 添加过渡请求 |
| 10 | ActivityRecord.java | setVisibility(boolean) | 3584 | 设置不可见入口 |
| 11 | ActivityRecord.java | setVisibility(boolean, boolean) | 5307 | 内部实现 |
| 12 | ActivityRecord.java | deferCommitVisibilityChange(boolean) | 5455 | 决定延迟提交 |
| 13 | ActivityRecord.java | mClosingApps.add(this) | 5497 | 加入关闭列表 |
| 14 | DisplayContent.java | executeAppTransition() | 5634 | 执行过渡 |
| 15 | AppTransitionController.java | handleAppTransitionReady() | 172 | 处理过渡入口 |
| 16 | AppTransitionController.java | transitionGoodToGo() | 174 | 检查是否准备好 |
| 17 | AppTransitionController.java | getTransitCompatType() | 263 | 确定过渡类型 |
| 18 | AppTransitionController.java | getAnimationTargets() | 475 | 获取动画目标 |
| 19 | AppTransitionController.java | getTransitContainerType() | 547 | 获取容器类型 |
| 20 | AppTransitionController.java | 返回 TRANSIT_OLD_ACTIVITY_CLOSE | 530 | Activity 关闭类型 |
| 21 | AppTransitionController.java | findAnimLayoutParamsToken() | 279 | 获取动画参数 |
| 22 | AppTransitionController.java | getAnimLp() | 560 | 获取 LayoutParams |
| 23 | AppTransitionController.java | applyAnimations(ArraySet<ActivityRecord>, ...) | 300 | 应用动画入口 |
| 24 | AppTransitionController.java | applyAnimations(ArraySet<WindowContainer>, ...) | 909 | 遍历容器应用 |
| 25 | WindowContainer.java | applyAnimation(...) | 3092 | 应用动画 |
| 26 | WindowContainer.java | applyAnimationUnchecked(...) | 3253 | 应用动画内部 |
| 27 | WindowContainer.java | getAnimationAdapter(...) | 3097 | 获取动画适配器 |
| 28 | WindowContainer.java | loadAnimation(...) | 3355 | 加载动画 |
| 29 | AppTransition.java | loadAnimation(...) | 764 | 加载动画 |
| 30 | AppTransition.java | mapOpenCloseTransitTypes(int, boolean) | 562 | 映射动画属性 |
| 31 | TransitionAnimation.java | loadDefaultAnimationAttr(int, int) | 351 | 加载默认动画 |
| 32 | TransitionAnimation.java | loadAnimationAttr(...) | 348 | 加载动画资源 |
| 33 | AppTransitionController.java | handleClosingApps() | 1201 | 处理关闭 App |
| 34 | ActivityRecord.java | commitVisibility(boolean, boolean) | 1208 | 提交可见性 |
| 35 | AppTransitionController.java | handleOpeningApps() | 1158 | 处理打开 App |
| 36 | ActivityRecord.java | showAllWindowsLocked() | 1180 | 显示所有窗口 |
六、总结
6.1 核心流程
- finish 请求发起: App 进程调用
Activity.finish()→ActivityClient.finishActivity()(Binder IPC) - 声明关闭过渡:
ActivityRecord.finishIfPossible()→DisplayContent.prepareAppTransition(TRANSIT_CLOSE)→AppTransition.prepareAppTransition() - 加入关闭列表:
ActivityRecord.setVisibility(false)→setVisibility(boolean, boolean)→deferCommitVisibilityChange(false)→mClosingApps.add(this) - 确定过渡类型:
handleAppTransitionReady()→getTransitCompatType()→getAnimationTargets()→getTransitContainerType()→ 返回TRANSIT_OLD_ACTIVITY_CLOSE - 应用动画:
applyAnimations()→WindowContainer.applyAnimation()→applyAnimationUnchecked()→getAnimationAdapter()→loadAnimation() - 加载动画资源:
AppTransition.loadAnimation()→mapOpenCloseTransitTypes()→TransitionAnimation.loadDefaultAnimationAttr()→ 从Animation.Activity样式加载
6.2 关键判断点
- Shell Transition 是否启用: 在
AppTransition.prepareAppTransition()中检查 - Activity 状态: RESUMED 状态会先 pause,非 RESUMED 状态直接执行过渡
- 容器类型判断:
getTransitContainerType()返回 TYPE_ACTIVITY 则使用 Activity 关闭动画
6.3 默认动画效果
- 关闭 Activity 退出动画: 向右平移 96dp + 透明度渐变,持续 450ms
- 下方 Activity 进入动画: 从左侧 -96dp 平移进入,持续 450ms