在 Launcher3 执行涉及其他应用窗口(即"远程窗口")的动画时,例如"点击桌面图标启动应用"或"从应用上滑回到桌面"的过渡动画,SurfaceControl
扮演着至关重要 的角色。它是实现这些跨进程、高性能、精确定制动画的核心技术。
SurfaceControl在源码中的使用
Launcher3中有几处非常经典的使用SurfaceControl的地方。
在分屏应用进入到最近任务,或者从最近任务启动应用时,涉及到分屏应用中间的bar条,这个bar条是属于SystemUI进程的,在Launcher中显示就属于远程窗口,因此需要通过SurfaceControl来进行更新操作。
启动分屏应用时bar条由隐藏到最终显示的过程就是通过SurfaceControl控制bar条的透明度来实现的。
源码如下:
java
public static ValueAnimator createSplitAuxiliarySurfacesAnimator(
@Nullable RemoteAnimationTarget[] nonApps, boolean shown,
@Nullable Consumer<ValueAnimator> animatorHandler) {
if (nonApps == null || nonApps.length == 0) {
return null;
}
List<SurfaceControl> auxiliarySurfaces = new ArrayList<>();
for (RemoteAnimationTarget target : nonApps) {
final SurfaceControl leash = target.leash;
if (target.windowType == TYPE_DOCK_DIVIDER && leash != null && leash.isValid()) {
auxiliarySurfaces.add(leash);
}
}
if (auxiliarySurfaces.isEmpty()) {
return null;
}
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
if (animatorHandler == null) {
// Apply the visibility directly without fade animation.
for (SurfaceControl leash : auxiliarySurfaces) {
t.setVisibility(leash, shown);
}
t.apply();
t.close();
return null;
}
ValueAnimator dockFadeAnimator = ValueAnimator.ofFloat(0f, 1f);
dockFadeAnimator.addUpdateListener(valueAnimator -> {
float progress = valueAnimator.getAnimatedFraction();
for (SurfaceControl leash : auxiliarySurfaces) {
if (leash != null && leash.isValid()) {
t.setAlpha(leash, shown ? progress : 1 - progress);
}
}
t.apply();
});
dockFadeAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
if (shown) {
for (SurfaceControl leash : auxiliarySurfaces) {
t.setLayer(leash, Integer.MAX_VALUE);
t.setAlpha(leash, 0);
t.show(leash);
}
t.apply();
}
}
@Override
public void onAnimationEnd(Animator animation) {
if (!shown) {
for (SurfaceControl leash : auxiliarySurfaces) {
if (leash != null && leash.isValid()) {
t.hide(leash);
}
}
t.apply();
}
t.close();
}
});
dockFadeAnimator.setDuration(SPLIT_DIVIDER_ANIM_DURATION);
animatorHandler.accept(dockFadeAnimator);
return dockFadeAnimator;
}
下来来详解SurfaceControl在Launcher中的角色以及为什么要使用SurfaceControl
SurfaceControl
的角色:
- 窗口/图层的句柄: 在 Android 图形系统中,每个窗口或可视元素最终都对应一个或多个图层 (Layer) ,这些图层由系统的合成器 (
SurfaceFlinger
) 负责管理和混合。SurfaceControl
是一个轻量级的句柄 (Handle) ,它代表了SurfaceFlinger
中的一个图层(Surface)。你可以把它想象成一个指向屏幕上某个"画板"的遥控器。 - 直接操作图层属性: 通过
SurfaceControl
,一个有权限的进程(在远程动画场景下,通常是 Launcher 或 SystemUI)可以直接、高效地 修改其代表的图层在SurfaceFlinger
中的各种属性,而无需 与创建这个图层的原始应用进程进行复杂的通信或等待其响应。这些属性包括:- 几何变换: 位置 (Position)、缩放 (Scale)、旋转 (Rotation) (通常通过设置变换矩阵
Matrix
实现)。 - 视觉效果: 透明度 (Alpha)、层级 (Z-order)、裁剪区域 (Window Crop)、圆角半径 (Corner Radius)、阴影 (Shadow Radius)、模糊 (Blur) 等。
- 几何变换: 位置 (Position)、缩放 (Scale)、旋转 (Rotation) (通常通过设置变换矩阵
- 跨进程动画的桥梁: 在远程动画中,系统 (
WindowManager
) 会将参与动画的窗口(例如正在打开的应用窗口、正在关闭的 Launcher 窗口、壁纸窗口)的SurfaceControl
(通常是一个称为 "Leash" 的特殊控制层)打包在RemoteAnimationTarget
对象中,传递给动画控制器(Launcher)。 - 动画执行者 (
SurfaceControl.Transaction
) : Launcher 拿到这些SurfaceControl
后,不会去修改对应应用的 View 属性,而是创建SurfaceControl.Transaction
对象。在动画的每一帧:- Launcher 计算出每个目标窗口图层应该具有的视觉属性(比如,应用窗口从图标大小放大到全屏,透明度从 0 到 1,裁剪区域从无到有,圆角从大变小)。
- 使用
Transaction
提供的方法(如setMatrix()
,setAlpha()
,setWindowCrop()
,setCornerRadius()
)为每个SurfaceControl
设置这些目标属性。 - 最后调用
transaction.apply()
原子性地 将这一帧的所有属性变更提交给SurfaceFlinger
。 SurfaceFlinger
在下一个 VSYNC 信号到来时,根据这些最新的属性来合成并显示屏幕内容,从而驱动了视觉上的动画效果。
为什么在远程动画中使用 SurfaceControl
?
使用 SurfaceControl
是实现现代 Android 流畅、复杂过渡动画的关键,原因如下:
- 高性能 (Performance): 直接在
SurfaceFlinger
(系统合成器)层面操作图层属性非常高效,通常能利用硬件加速。这避免了在应用进程内部进行复杂的 View 布局、绘制或属性动画,这些操作可能更耗资源且容易引发卡顿 (Jank)。 - 精确同步 (Synchronization): 对于涉及多个应用窗口(跨进程)的过渡动画(如应用启动/关闭、分屏),需要精确地同步它们的动画。通过
SurfaceControl.Transaction
,Launcher 可以原子性地更新所有相关图层的属性,确保它们在同一帧内发生变化,实现完美的视觉同步。如果依赖各个应用自己执行动画,几乎不可能做到如此精确的同步。 - 强大控制力 (Control):
SurfaceControl
API 提供了对图层视觉属性的底层、细粒度控制,使得 Launcher 可以实现非常复杂的动画效果,例如从图标到窗口的平滑变形、窗口内容的裁剪、圆角变化等,这些效果很难通过传统的 View 动画或窗口动画(ActivityOptions
)实现得如此精细。 - 解耦 (Decoupling): 被动画的应用(例如正在启动的应用)不需要 主动参与这个由 Launcher 控制的过渡动画。应用只需要正常地将自己的内容绘制到它的 Surface 上即可。Launcher 通过
SurfaceControl
在外部"指挥"SurfaceFlinger
如何变换和展示这个 Surface。这大大降低了应用和系统过渡动画之间的耦合度。 - 无缝体验 (Seamlessness):
SurfaceControl
使得元素(如图标)看起来能够"无缝地"跨越进程边界变形成为另一个应用的窗口,提供了非常连贯和自然的视觉体验。
总结:
在 Launcher 对远程窗口执行动画的过程中,SurfaceControl
充当了底层图层(Surface)的直接控制器 。Launcher 通过它,绕开了应用进程,直接与系统合成器 SurfaceFlinger
交互,以高性能、精确同步的方式驱动应用窗口的几何变换和视觉效果,从而实现了流畅、复杂且跨进程的过渡动画。这是现代 Android 系统动画(尤其是 Quickstep 手势动画)的核心技术基础。