基于 AOSP 15 (Android 15) 源码,分析窗口动画的添加、执行、移除完整流程。
目录
1. 架构概览
窗口动画系统分为三层:
scss
┌──────────────────────────────────────────────────┐
│ 应用层 (App Process) │
│ RemoteAnimationRunner / View Animation │
├──────────────────────────────────────────────────┤
│ 框架层 (Framework Services) │
│ AppTransitionController → AppTransition │
│ → WindowContainer.applyAnimation() │
│ → SurfaceAnimator.startAnimation() │
├──────────────────────────────────────────────────┤
│ 执行层 (Animation Runner) │
│ SurfaceAnimationRunner (AnimationThread) │
│ → ValueAnimator → Transaction.apply() │
└──────────────────────────────────────────────────┘
核心设计思路:通过 Leash(牵引绳)机制实现动画------创建一个新的 SurfaceControl(Leash),将目标窗口的 Surface 重新挂载到 Leash 上,然后对 Leash 做变换(位移、缩放、透明度等),动画结束后将 Surface 重新挂回原父节点并销毁 Leash。
2. 核心类介绍
2.1 WindowAnimator
路径 : services/core/java/com/android/server/wm/WindowAnimator.java
全局单例,驱动每帧动画更新。通过 Choreographer 注册 FrameCallback,在每个 VSync 信号到来时执行 animate() 方法。
java
// WindowAnimator.java
WindowAnimator(final WindowManagerService service) {
// ...
mChoreographer = Choreographer.getSfInstance(); // 使用 SurfaceFlinger 的 VSync
mAnimationFrameCallback = frameTimeNs -> {
synchronized (mService.mGlobalLock) {
mAnimationFrameCallbackScheduled = false;
animate(frameTimeNs); // 核心动画帧回调
}
};
}
2.2 SurfaceAnimator
路径 : services/core/java/com/android/server/wm/SurfaceAnimator.java
动画核心控制器,管理 Leash 的创建与销毁,协调动画的启动、取消和完成回调。
每个 WindowContainer 持有一个 SurfaceAnimator 实例。
2.3 SurfaceAnimationRunner
路径 : services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
在不持有 WindowManager 锁的情况下运行动画。在 SurfaceAnimationThread 上使用 ValueAnimator 驱动动画,通过 SurfaceControl.Transaction 应用变换到 Leash。
2.4 AnimationAdapter 接口
路径 : services/core/java/com/android/server/wm/AnimationAdapter.java
动画适配器接口,桥接 SurfaceAnimator 和实际执行动画的组件。主要实现:
- LocalAnimationAdapter :本地动画,通过
SurfaceAnimationRunner执行 - RemoteAnimationController:远程动画,在应用进程中执行(如 Launcher 的动画)
2.5 WindowStateAnimator
路径 : services/core/java/com/android/server/wm/WindowStateAnimator.java
单个窗口(WindowState)的动画和 Surface 状态管理,负责窗口进入/退出动画的应用。
2.6 AppTransitionController
路径 : services/core/java/com/android/server/wm/AppTransitionController.java
检查 App 转场动画是否就绪,解析动画属性,执行可见性变更。是 App 转场动画的入口控制器。
3. 动画添加流程
3.1 触发入口:窗口绘制完成到进入动画
窗口动画的触发起点是窗口绘制完成(Draw 完成),从 WindowStateAnimator.commitFinishDrawingLocked() 开始,完整链路如下:
3.1.1 绘制完成:commitFinishDrawingLocked
当客户端完成一帧绘制后,WMS 调用 finishDrawingLocked() 将 DrawState 从 DRAW_PENDING 推进到 COMMIT_DRAW_PENDING。随后在布局流程中调用 commitFinishDrawingLocked():
java
// WindowStateAnimator.java
boolean commitFinishDrawingLocked() {
// 检查状态必须是 COMMIT_DRAW_PENDING 或 READY_TO_SHOW
if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
return false;
}
mDrawState = READY_TO_SHOW;
final ActivityRecord activity = mWin.mActivityRecord;
// 如果没有 ActivityRecord,或 Activity 允许显示窗口,或是 StartingWindow → 调用 performShow
if (activity == null || activity.canShowWindows()
|| mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
result = mWin.performShowLocked(); // → 关键跳转点
}
return result;
}
DrawState 状态流转:
NO_SURFACE → DRAW_PENDING → COMMIT_DRAW_PENDING → READY_TO_SHOW → HAS_DRAWN
↑ ↑
commitFinish performShow
DrawingLocked Locked 设置
3.1.2 显示窗口:performShowLocked
performShowLocked() 负责将窗口从"准备好显示"推进到"已显示",并在此处触发进入动画:
java
// WindowState.java
boolean performShowLocked() {
// 检查状态必须是 READY_TO_SHOW
if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
return false;
}
mWmService.enableScreenIfNeededLocked();
// ★ 触发进入动画 ★
mWinAnimator.applyEnterAnimationLocked();
mWinAnimator.mLastAlpha = -1; // 强制下一帧 prepareSurface 更新 alpha
mWinAnimator.mDrawState = HAS_DRAWN;
mWmService.scheduleAnimationLocked(); // 调度动画帧
// 递归显示子窗口
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = mChildren.get(i);
if (c.mWinAnimator.mSurfaceControl != null) {
c.performShowLocked();
}
}
return true;
}
注意 :scheduleAnimationLocked() 在此处被调用,确保 WindowAnimator 在下一个 VSync 执行 animate(),驱动动画帧更新。
3.1.3 应用进入动画:applyEnterAnimationLocked
根据窗口是否首次显示,选择 TRANSIT_ENTER(首次进入)或 TRANSIT_SHOW(重新显示)转场类型:
java
// WindowStateAnimator.java
void applyEnterAnimationLocked() {
final int transit;
if (mEnterAnimationPending) {
mEnterAnimationPending = false;
transit = WindowManagerPolicy.TRANSIT_ENTER; // 首次进入动画
} else {
transit = WindowManagerPolicy.TRANSIT_SHOW; // 重新显示动画
}
// 排除三类窗口:
// 1. TYPE_BASE_APPLICATION --- 应由 ActivityRecord 控制(App Transition)
// 2. Wallpaper --- 应由 WallpaperController 控制
// 3. StartingWindow 下的窗口 --- 跳过
if (mAttrType != TYPE_BASE_APPLICATION && !mWin.mIsWallpaper
&& !(mWin.mActivityRecord != null && mWin.mActivityRecord.hasStartingWindow())) {
applyAnimationLocked(transit, true /* isEntrance */);
}
// 通知无障碍服务窗口转场
if (mService.mAccessibilityController.hasCallbacks()) {
mService.mAccessibilityController.onWindowTransition(mWin, transit);
}
}
为什么排除 TYPE_BASE_APPLICATION? 应用主窗口的动画由 AppTransitionController 统一管理(通过 mOpeningApps/mClosingApps),不走 WindowState 级别的进入动画,以保证所有 Activity 窗口动画的协调性。
3.1.4 选择并加载动画:applyAnimationLocked
根据转场类型选择具体的 Animation 资源:
java
// WindowStateAnimator.java
boolean applyAnimationLocked(int transit, boolean isEntrance) {
// 如果已经在运行同类型的动画,不重复应用
if (mWin.isAnimating() && mAnimationIsEntrance == isEntrance) {
return true;
}
if (mWin.mControllableInsetProvider != null) {
return false; // Inset 提供者的动画由 Inset 控制目标驱动
}
if (mWin.mToken.okToAnimate()) {
// 步骤 1:通过 DisplayPolicy 选择动画资源 ID
int anim = mWin.getDisplayContent().getDisplayPolicy().selectAnimation(mWin, transit);
Animation a = null;
if (anim != DisplayPolicy.ANIMATION_STYLEABLE) {
// 系统内置动画,直接加载
if (anim != DisplayPolicy.ANIMATION_NONE) {
a = AnimationUtils.loadAnimation(mContext, anim);
}
} else {
// 从窗口的 WindowAnimation style 属性加载
// transit=ENTER → windowEnterAnimation
// transit=EXIT → windowExitAnimation
// transit=SHOW → windowShowAnimation
// transit=HIDE → windowHideAnimation
int attr = -1;
switch (transit) {
case TRANSIT_ENTER:
attr = R.styleable.WindowAnimation_windowEnterAnimation;
break;
case TRANSIT_EXIT:
attr = R.styleable.WindowAnimation_windowExitAnimation;
break;
case TRANSIT_SHOW:
attr = R.styleable.WindowAnimation_windowShowAnimation;
break;
case TRANSIT_HIDE:
attr = R.styleable.WindowAnimation_windowHideAnimation;
break;
}
if (attr >= 0) {
a = mWin.getDisplayContent().mAppTransition.loadAnimationAttr(
mWin.mAttrs, attr, TRANSIT_OLD_NONE);
}
}
// 步骤 2:启动动画
if (a != null) {
mWin.startAnimation(a); // → 进入 3.2 节
mAnimationIsEntrance = isEntrance;
}
} else {
mWin.cancelAnimation(); // 不允许动画时直接取消
}
return mWin.isAnimating(0, ANIMATION_TYPE_WINDOW_ANIMATION);
}
3.2 创建动画适配器并启动:WindowState.startAnimation
WindowState.startAnimation() 将 Animation 对象封装为 LocalAnimationAdapter,然后通过 WindowContainer.startAnimation() 交给 SurfaceAnimator:
java
// WindowState.java
void startAnimation(Animation anim) {
if (mControllableInsetProvider != null) return;
// 初始化 Animation 的尺寸信息
final DisplayInfo displayInfo = getDisplayInfo();
anim.initialize(mWindowFrames.mFrame.width(), mWindowFrames.mFrame.height(),
displayInfo.appWidth, displayInfo.appHeight);
anim.restrictDuration(MAX_ANIMATION_DURATION);
anim.scaleCurrentDuration(mWmService.getWindowAnimationScaleLocked());
// 计算窗口在 Surface 坐标系中的位置
final Point position = new Point();
transformFrameToSurfacePosition(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top, position);
// 创建 LocalAnimationAdapter
final AnimationAdapter adapter = new LocalAnimationAdapter(
new WindowAnimationSpec(anim, position, false /* canSkipFirstFrame */,
0 /* windowCornerRadius */),
mWmService.mSurfaceAnimationRunner);
// 根据是否有 ActivityRecord 选择不同 Transaction
final Transaction t = mActivityRecord != null
? getSyncTransaction() : getPendingTransaction();
startAnimation(t, adapter); // → WindowContainer.startAnimation()
commitPendingTransaction();
}
3.3 WindowContainer.startAnimation → SurfaceAnimator.startAnimation
WindowContainer.startAnimation() 直接委托给 SurfaceAnimator:
java
// WindowContainer.java
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type, ...) {
mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
animationCancelledCallback, snapshotAnim, mSurfaceFreezer);
}
3.4 SurfaceAnimator.startAnimation --- Leash 创建
这是动画添加的核心步骤,负责创建 Leash 并启动动画执行:
java
// SurfaceAnimator.java
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type, ...) {
// 1. 取消已有动画(标记为 restarting)
cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
// 2. 保存动画引用
mAnimation = anim;
mAnimationType = type;
// 3. 获取目标 Surface
final SurfaceControl surface = mAnimatable.getSurfaceControl();
if (surface == null) {
cancelAnimation();
return;
}
// 4. 创建 Leash(动画牵引 Surface)
mLeash = createAnimationLeash(mAnimatable, surface, t, type,
mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(),
0 /* x */, 0 /* y */, hidden, mService.mTransactionFactory);
// 5. 通知 Animatable Leash 已创建
mAnimatable.onAnimationLeashCreated(t, mLeash);
// 6. 通知 Animatable 即将开始动画
mAnimatable.onLeashAnimationStarting(t, mLeash);
// 7. 启动动画(交给 AnimationAdapter 执行)
mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
}
3.5 Leash 创建细节:createAnimationLeash
java
// SurfaceAnimator.java
static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface,
Transaction t, @AnimationType int type, int width, int height, ...) {
// 创建一个新的 EffectLayer 作为 Leash
final SurfaceControl leash = animatable.makeAnimationLeash()
.setParent(animatable.getAnimationLeashParent()) // 挂到动画专用父节点
.setName(surface + " - animation-leash of " + animationTypeToString(type))
.setHidden(hidden)
.setEffectLayer()
.build();
// 设置初始裁剪区域和位置
t.setWindowCrop(leash, width, height);
t.setPosition(leash, x, y);
t.show(leash);
t.setAlpha(leash, hidden ? 0 : 1);
// 关键步骤:将目标 Surface 重新挂载到 Leash 下
t.reparent(surface, leash);
return leash;
}
Surface 层级变化:
makefile
动画前:
ParentSurface
└── TargetSurface
动画中:
AnimationLeashParent
└── Leash (动画变换作用于此)
└── TargetSurface
动画后:
ParentSurface
└── TargetSurface (恢复原位)
3.6 补充:App Transition 路径(Activity 级别转场)
上面 3.1~3.5 分析的是窗口级别 的进入动画路径(非 TYPE_BASE_APPLICATION 窗口)。对于应用主窗口,动画由 AppTransitionController 统一管理:
scss
AppTransitionController.handleAppTransitionReady()
├─ transitionGoodToGo() 检查所有 App 窗口是否就绪
├─ getTransitCompatType() 确定转场类型(如 TRANSIT_OLD_ACTIVITY_OPEN)
├─ getAnimationTargets() 收集动画目标 WindowContainer
└─ applyAnimations()
└─ wc.applyAnimation()
└─ getAnimationAdapter() 获取 AnimationAdapter
├─ [远程动画] RemoteAnimationController
└─ [本地动画] AppTransition.loadAnimation() → WindowAnimationSpec → LocalAnimationAdapter
该路径最终同样走到 WindowContainer.startAnimation() → SurfaceAnimator.startAnimation(),与窗口级动画在 Leash 创建和动画执行阶段完全一致。
4. 动画执行流程
4.1 LocalAnimationAdapter.startAnimation
java
// LocalAnimationAdapter.java:64
public void startAnimation(SurfaceControl animationLeash, Transaction t,
@AnimationType int type, OnAnimationFinishedCallback finishCallback) {
mAnimator.startAnimation(mSpec, animationLeash, t,
() -> finishCallback.onAnimationFinished(type, this));
}
4.2 SurfaceAnimationRunner.startAnimation
java
// SurfaceAnimationRunner.java
void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
Runnable finishCallback) {
synchronized (mLock) {
final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash, finishCallback);
// 加入待启动队列
mPendingAnimations.put(animationLeash, runningAnim);
// 通过 Choreographer 在下一帧启动
if (!mAnimationStartDeferred && mPreProcessingAnimations.isEmpty()) {
mChoreographer.postFrameCallback(this::startAnimations);
}
// 立即应用初始变换(第 0 帧)
applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
}
}
4.3 ValueAnimator 驱动逐帧更新
java
// SurfaceAnimationRunner.java:281
private void startAnimationLocked(RunningAnimation a) {
final ValueAnimator anim = mAnimatorFactory.makeAnimator();
anim.setDuration(a.mAnimSpec.getDuration());
// 每帧更新回调
anim.addUpdateListener(animation -> {
if (!a.mCancelled) {
long currentPlayTime = anim.getCurrentPlayTime();
applyTransformation(a, mFrameTransaction, currentPlayTime);
}
scheduleApplyTransaction(); // 调度 Transaction 提交
});
// 动画结束回调
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mRunningAnimations.remove(a.mLeash);
if (!a.mCancelled) {
// 在 AnimationThread 上执行完成回调
mAnimationThreadHandler.post(a.mFinishCallback);
}
}
});
a.mAnim = anim;
mRunningAnimations.put(a.mLeash, a);
anim.start();
}
4.4 逐帧变换应用
java
// SurfaceAnimationRunner.java
private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
}
// WindowAnimationSpec.java
public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
tmp.transformation.clear();
mAnimation.getTransformation(currentPlayTime, tmp.transformation); // 从 Animation 获取当前变换
tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats); // 设置矩阵
t.setAlpha(leash, tmp.transformation.getAlpha()); // 设置透明度
// 设置裁剪区域
if (tmp.transformation.hasClipRect()) {
t.setWindowCrop(leash, tmp.transformation.getClipRect());
}
}
4.5 Transaction 提交
java
// SurfaceAnimationRunner.java
private void applyTransaction() {
mFrameTransaction.setAnimationTransaction(); // 标记为动画事务
mFrameTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId()); // 关联 VSync
mFrameTransaction.apply(); // 提交到 SurfaceFlinger
mApplyScheduled = false;
}
4.6 WindowAnimator.animate() 的角色
WindowAnimator 在每帧 VSync 时执行,负责:
- 调用
dc.updateWindowsForAnimator()更新窗口动画状态 - 调用
dc.prepareSurfaces()准备 Surface - 合并各 DisplayContent 的 pending Transaction
- 统一 apply 整个 Transaction
java
// WindowAnimator.java
private void animate(long frameTimeNs) {
scheduleAnimation(); // 预先调度下一帧(持续反压)
for (int i = 0; i < numDisplays; i++) {
final DisplayContent dc = root.getChildAt(i);
dc.updateWindowsForAnimator(); // 更新窗口动画
dc.prepareSurfaces(); // 准备 Surface
}
// 检查是否还有动画在运行
for (int i = 0; i < numDisplays; i++) {
if (dc.isAnimating(animationFlags, ANIMATION_TYPE_ALL)) {
rootAnimating = true;
}
mTransaction.merge(dc.getPendingTransaction()); // 合并 Transaction
}
mTransaction.apply(); // 统一提交
}
5. 动画移除流程
5.1 正常结束
当 SurfaceAnimationRunner 中的 ValueAnimator 播放完毕时:
scss
ValueAnimator.onAnimationEnd()
→ mAnimationThreadHandler.post(a.mFinishCallback)
→ mInnerAnimationFinishedCallback.onAnimationFinished()
mInnerAnimationFinishedCallback 是在 SurfaceAnimator 构造时创建的:
java
// SurfaceAnimator.java
private OnAnimationFinishedCallback getFinishedCallback(...) {
return (type, anim) -> {
synchronized (mService.mGlobalLock) {
if (anim != mAnimation) return; // 动画已被替换,忽略
final Runnable resetAndInvokeFinish = () -> {
if (anim != mAnimation) return; // 再次检查
reset(mAnimatable.getSyncTransaction(), true /* destroyLeash */);
// 回调通知
if (staticAnimationFinishedCallback != null) {
staticAnimationFinishedCallback.onAnimationFinished(type, anim);
}
if (animationFinishCallback != null) {
animationFinishCallback.onAnimationFinished(type, anim);
}
};
// 检查是否需要延迟结束
if (!(mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)
|| anim.shouldDeferAnimationFinish(resetAndInvokeFinish))) {
resetAndInvokeFinish.run();
}
}
};
}
5.2 reset --- 清理 Leash
java
// SurfaceAnimator.java
private void reset(Transaction t, boolean destroyLeash) {
mService.mAnimationTransferMap.remove(mAnimation);
mAnimation = null;
mSurfaceAnimationFinishedCallback = null;
mAnimationType = ANIMATION_TYPE_NONE;
// 清理快照
if (mSnapshot != null) {
mSnapshot.cancelAnimation(t, !destroyLeash);
mSnapshot = null;
}
if (mLeash == null) return;
SurfaceControl leash = mLeash;
mLeash = null;
// 移除 Leash,将 Surface 重新挂回原父节点
final boolean scheduleAnim = removeLeash(t, mAnimatable, leash, destroyLeash);
mAnimationFinished = false;
if (scheduleAnim) {
mService.scheduleAnimationLocked();
}
}
5.3 removeLeash --- Surface 重新挂载
java
// SurfaceAnimator.java
static boolean removeLeash(Transaction t, Animatable animatable, SurfaceControl leash,
boolean destroy) {
final SurfaceControl surface = animatable.getSurfaceControl();
final SurfaceControl parent = animatable.getParentSurfaceControl();
final SurfaceControl curAnimationLeash = animatable.getAnimationLeash();
// 判断是否需要重新挂载
final boolean reparent = surface != null && (curAnimationLeash == null
|| curAnimationLeash.equals(leash));
if (reparent) {
// 将 Surface 重新挂回原始父节点
if (surface.isValid() && parent != null && parent.isValid()) {
t.reparent(surface, parent);
}
}
// 销毁 Leash
if (destroy) {
t.remove(leash);
}
// 通知 Animatable Leash 已丢失
if (reparent) {
animatable.onAnimationLeashLost(t);
}
return scheduleAnim;
}
5.4 主动取消动画
java
// SurfaceAnimator.java
private void cancelAnimation(Transaction t, boolean restarting, boolean forwardCancel) {
final SurfaceControl leash = mLeash;
final AnimationAdapter animation = mAnimation;
// 重置内部状态
reset(t, false);
if (animation != null) {
if (forwardCancel) {
// 通知动画适配器动画被取消
animation.onAnimationCancelled(leash);
// SurfaceAnimationRunner 收到后取消 ValueAnimator
}
if (!restarting) {
// 通知外部回调动画结束
if (mStaticAnimationFinishedCallback != null) {
mStaticAnimationFinishedCallback.onAnimationFinished(animationType, animation);
}
}
}
if (forwardCancel) {
// 取消快照动画
if (snapshot != null) snapshot.cancelAnimation(t, false);
// 移除 Leash
if (leash != null) {
t.remove(leash);
mService.scheduleAnimationLocked();
}
}
}
5.5 SurfaceAnimationRunner 处理取消
java
// SurfaceAnimationRunner.java
void onAnimationCancelled(SurfaceControl leash) {
synchronized (mLock) {
// 从待启动队列中移除
if (mPendingAnimations.containsKey(leash)) {
mPendingAnimations.remove(leash);
return;
}
// 从预处理队列中移除
if (mPreProcessingAnimations.containsKey(leash)) {
mPreProcessingAnimations.remove(leash);
return;
}
// 从运行中队列中移除并取消
final RunningAnimation anim = mRunningAnimations.get(leash);
if (anim != null) {
mRunningAnimations.remove(leash);
synchronized (mCancelLock) {
anim.mCancelled = true;
}
mSurfaceAnimationHandler.post(() -> {
anim.mAnim.cancel(); // 取消 ValueAnimator
applyTransaction(); // 提交最终状态
});
}
}
}
5.6 WindowState 动画结束
对于 WindowState 级别的动画(非 App 转场),结束回调链:
scss
SurfaceAnimator.mInnerAnimationFinishedCallback
→ WindowContainer.doAnimationFinished()
→ WindowState.onAnimationFinished()
→ WindowStateAnimator.onAnimationFinished()
→ WindowState.checkPolicyVisibilityChange()
→ WindowState.onExitAnimationDone()
java
// WindowStateAnimator.java
void onAnimationFinished() {
mWin.checkPolicyVisibilityChange();
// 请求重新布局
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
if (displayContent.mWallpaperController.isWallpaperTarget(mWin)) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
// 更新 Activity 可见性
if (mWin.mActivityRecord != null) {
mWin.mActivityRecord.updateReportedVisibilityLocked();
}
}
6. 完整时序图
6.1 窗口级进入动画完整流程(从 commitFinishDrawingLocked 开始)
scss
客户端完成绘制(finishDrawing)
│
▼
WindowStateAnimator.finishDrawingLocked()
│ mDrawState: DRAW_PENDING → COMMIT_DRAW_PENDING
│
▼
WindowStateAnimator.commitFinishDrawingLocked()
│ mDrawState: COMMIT_DRAW_PENDING → READY_TO_SHOW
│ 检查是否可以显示(无 ActivityRecord / canShowWindows / StartingWindow)
│
▼
WindowState.performShowLocked()
│ 检查 mDrawState == READY_TO_SHOW && isReadyForDisplay()
│
├─ mWinAnimator.applyEnterAnimationLocked() ★ 触发进入动画 ★
├─ mDrawState = HAS_DRAWN
├─ scheduleAnimationLocked() 调度动画帧
│
▼
WindowStateAnimator.applyEnterAnimationLocked()
│
├─ 确定转场类型: TRANSIT_ENTER(首次)或 TRANSIT_SHOW(重新显示)
├─ 排除 TYPE_BASE_APPLICATION / Wallpaper / StartingWindow 下的窗口
│
▼
WindowStateAnimator.applyAnimationLocked(transit, isEntrance=true)
│
├─ okToAnimate() 检查是否可以动画
├─ selectAnimation() 或 loadAnimationAttr() 加载 Animation 资源
│ ├─ TRANSIT_ENTER → WindowAnimation_windowEnterAnimation
│ └─ TRANSIT_SHOW → WindowAnimation_windowShowAnimation
│
▼ (a != null)
WindowState.startAnimation(a)
│
├─ anim.initialize() / restrictDuration() / scaleCurrentDuration()
├─ new WindowAnimationSpec(anim, position, ...)
├─ new LocalAnimationAdapter(spec, mSurfaceAnimationRunner)
│
▼
WindowContainer.startAnimation(t, adapter)
│
▼
SurfaceAnimator.startAnimation()
│
├─ cancelAnimation(restarting=true) 取消已有动画
├─ createAnimationLeash() 创建 Leash
│ └─ t.reparent(surface, leash) Surface 挂到 Leash 下
├─ onAnimationLeashCreated() 通知 Leash 创建
├─ onLeashAnimationStarting() 通知动画即将开始
│
▼
AnimationAdapter.startAnimation(leash, t, type, finishCallback)
│
▼ [LocalAnimationAdapter]
SurfaceAnimationRunner.startAnimation()
│
├─ new RunningAnimation(spec, leash, finishCallback)
├─ mPendingAnimations.put(leash, runningAnim)
├─ mChoreographer.postFrameCallback(startAnimations)
▼ [下一帧 VSync]
startAnimations()
│
▼
startAnimationLocked()
│
├─ new ValueAnimator(duration)
├─ anim.addUpdateListener(→ applyTransformation())
├─ anim.addListener(→ onAnimationEnd → finishCallback)
├─ mRunningAnimations.put(leash, a)
├─ anim.start()
│
▼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
│ [每帧循环] │
▼ │
applyTransformation() │
├─ spec.apply(t, leash, time) │
│ ├─ t.setMatrix() │
│ ├─ t.setAlpha() │
│ └─ t.setWindowCrop() │
└─ scheduleApplyTransaction() │
└─ applyTransaction() │
└─ t.apply() │
│ │
▼ │
SurfaceFlinger 合成 │
│ │
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┘
│
▼ [动画播放完毕]
ValueAnimator.onAnimationEnd()
│
▼
mFinishCallback (→ mInnerAnimationFinishedCallback)
│
▼
SurfaceAnimator 内部完成回调
│
├─ shouldDeferAnimationFinish() 检查是否延迟结束
│
▼
reset(syncTransaction, destroyLeash=true)
│
├─ mAnimation = null
├─ mLeash = null
│
▼
removeLeash()
│
├─ t.reparent(surface, parent) Surface 挂回原父节点
├─ t.remove(leash) 销毁 Leash
├─ animatable.onAnimationLeashLost(t)
│
▼
staticAnimationFinishedCallback.onAnimationFinished()
│
▼
WindowContainer.doAnimationFinished()
│
▼
ActivityRecord/WindowState.onAnimationFinished()
│
├─ 更新可见性
├─ 请求重新布局
└─ 通知上层动画完成
6.2 远程动画流程
scss
AppTransitionController.handleAppTransitionReady()
│
▼
WindowContainer.getAnimationAdapter()
│
├─ controller != null (RemoteAnimationController)
│
▼
RemoteAnimationController.createRemoteAnimationRecord()
│
▼
SurfaceAnimator.startAnimation()
├─ 创建 Leash
└─ mAnimation.startAnimation(leash, t, type, finishCallback)
│
▼ [RemoteAnimationAdapter]
RemoteAnimationController.onStartAnimation()
│
├─ 构建 RemoteAnimationTarget[] (包含 leash)
├─ 跨进程调用 mRemoteAnimationAdapter.getRunner().onStartAnimation()
│
▼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
│ [应用进程] │
▼ │
RemoteAnimationRunner.onStartAnimation() │
│ │
├─ 操作 leash 的 Transaction │
├─ 完成后调用 │
│ finishCallback.onAnimationFinished()
│ │
▼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┘
│
▼ [回到系统进程]
SurfaceAnimator 内部完成回调
│
▼
reset() → removeLeash() (与本地动画相同)
7. 关键源码位置索引
| 类 | 路径 | 职责 |
|---|---|---|
WindowAnimator |
services/wm/WindowAnimator.java |
全局动画帧驱动 |
SurfaceAnimator |
services/wm/SurfaceAnimator.java |
Leash 管理与动画生命周期 |
SurfaceAnimationRunner |
services/wm/SurfaceAnimationRunner.java |
无锁动画执行(ValueAnimator) |
LocalAnimationAdapter |
services/wm/LocalAnimationAdapter.java |
本地动画适配器 |
AnimationAdapter |
services/wm/AnimationAdapter.java |
动画适配器接口 |
WindowAnimationSpec |
services/wm/WindowAnimationSpec.java |
窗口动画规格(变换计算) |
AppTransitionController |
services/wm/AppTransitionController.java |
App 转场控制器 |
AppTransition |
services/wm/AppTransition.java |
转场动画状态管理 |
RemoteAnimationController |
services/wm/RemoteAnimationController.java |
远程动画控制器 |
WindowStateAnimator |
services/wm/WindowStateAnimator.java |
单窗口动画状态 |
WindowContainer |
services/wm/WindowContainer.java |
动画目标容器基类 |
SurfaceAnimationThread |
services/wm/SurfaceAnimationThread.java |
动画专用线程 |
AnimationThread |
server/AnimationThread.java |
系统动画线程 |
所有路径基于
frameworks/base/services/core/java/com/android/server/wm/
8. 动画类型
SurfaceAnimator 定义了以下动画类型(位掩码):
| 类型 | 值 | 说明 |
|---|---|---|
ANIMATION_TYPE_NONE |
0 | 无动画 |
ANIMATION_TYPE_APP_TRANSITION |
1 | App 转场动画 |
ANIMATION_TYPE_SCREEN_ROTATION |
2 | 屏幕旋转动画 |
ANIMATION_TYPE_DIMMER |
4 | 调光动画 |
ANIMATION_TYPE_RECENTS |
8 | 最近任务动画 |
ANIMATION_TYPE_WINDOW_ANIMATION |
16 | 窗口动画(非 Activity) |
ANIMATION_TYPE_INSETS_CONTROL |
32 | 插入控制动画 |
ANIMATION_TYPE_TOKEN_TRANSFORM |
64 | Token 变换动画 |
ANIMATION_TYPE_STARTING_REVEAL |
128 | 启动窗口揭显动画 |
ANIMATION_TYPE_PREDICT_BACK |
256 | 预测返回手势动画 |
9. 总结
动画添加:3 步走
- 选择动画 ---
AppTransitionController确定转场类型,AppTransition加载具体 Animation - 创建 Leash ---
SurfaceAnimator.startAnimation()创建 Leash 并将 Surface 重新挂载 - 启动执行 ---
SurfaceAnimationRunner通过ValueAnimator逐帧驱动变换
动画执行:逐帧循环
ValueAnimator每帧触发addUpdateListenerWindowAnimationSpec.apply()计算 Matrix/Alpha/Crop 并写入 TransactionapplyTransaction()提交到 SurfaceFlinger
动画移除:2 条路径
- 正常结束 ---
ValueAnimator.onAnimationEnd()→finishCallback→reset()→removeLeash() - 主动取消 ---
cancelAnimation()→animation.onAnimationCancelled()→reset()→removeLeash()
核心清理逻辑统一在 removeLeash() 中:将 Surface 重新挂回原父节点,销毁 Leash,通知 onAnimationLeashLost()。