Launcher3中,有一个类在跟桌面相关的各种动画中扮演着非常关键的角色,这个类就是QuickstepTransitionManager。
QuickstepTransitionManager在aosp中的路径为:aosp/packages/apps/Launcher3/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
接下来我们来深入分析 QuickstepTransitionManager.java
这个类。它是 Quickstep (Launcher3 的手势导航和过渡动画核心实现) 中至关重要的部分,负责管理和协调各种复杂的应用程序启动和关闭过渡动画。
核心作用 (Core Role):
QuickstepTransitionManager
的主要职责是定义、注册和执行 当用户在 Launcher 和其他应用程序之间切换时所看到的窗口过渡动画。这包括:
-
应用启动动画: 当用户从 Launcher (如点击图标、小部件或从概览启动任务) 启动一个应用程序时,
QuickstepTransitionManager
负责创建和运行动画,使得 Launcher 界面元素(如图标、背景、工作区)能够平滑地过渡到应用程序窗口的出现。 -
应用关闭动画 (返回桌面): 当用户从一个应用程序通过手势或按键返回到 Launcher (桌面) 时,它负责创建和运行动画,使得应用程序窗口能够平滑地过渡(通常是缩小)到 Launcher 上的对应目标(图标、小部件或屏幕中心),同时 Launcher 界面元素(工作区、背景等)恢复显示。
-
概览启动动画: 管理从概览 (RecentsView) 启动任务时的特殊过渡动画。
-
特殊场景处理: 处理一些特殊情况下的动画,如从锁屏解锁进入 Launcher、从小部件启动应用、从预测行启动应用等。
-
动画参数计算: 计算动画所需的各种参数,如窗口的起始/结束位置、缩放比例、透明度、圆角、裁剪区域等。
-
系统动画注册: 向 Android 系统的窗口管理器 (WindowManager) 注册 这些自定义的过渡动画。这通过
RemoteAnimationAdapter
(旧版) 或RemoteTransition
(新版 Shell Transitions) 实现,使得系统在进行窗口切换时,能够调用 Launcher 提供的动画逻辑来取代默认的窗口动画。
简单来说,QuickstepTransitionManager
就是 Launcher3 中负责**"让应用打开和关闭看起来很酷很流畅"**的幕后导演。
工作原理 (How it Works):
其工作原理主要基于 Android 提供的远程动画 (Remote Animations / Transitions) 机制:
- 注册:
- 在 Launcher 启动时 (或特定时机),
QuickstepTransitionManager
会通过SystemUiProxy
向系统注册自定义的动画。 - 它会指定哪些窗口切换场景(由
WindowManager.TransitionType
或TransitionFilter
定义,例如TRANSIT_OLD_WALLPAPER_OPEN
,TRANSIT_OPEN/CLOSE
组合等)应该使用 Launcher 提供的动画逻辑。 - 注册的核心是一个实现了
RemoteAnimationRunnerCompat
或IRemoteTransition
接口的对象 (通常是LauncherAnimationRunner
的实例)。
- 在 Launcher 启动时 (或特定时机),
java
// quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
protected void setupViews() {
super.setupViews();
......省略
mAppTransitionManager = buildAppTransitionManager();
//向系统注册自定义动画
mAppTransitionManager.registerRemoteAnimations();
......省略
}
java
//quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
public void registerRemoteAnimations() {
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
addRemoteAnimations(definition);
mLauncher.registerRemoteAnimations(definition);
}
/**
* Adds remote animations to a {@link RemoteAnimationDefinition}. May be overridden to add
* additional animations.
*/
//quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
private void addRemoteAnimations(RemoteAnimationDefinition definition) {
mWallpaperOpenRunner = createWallpaperOpenRunner(false /* fromUnlock */);
definition.addRemoteAnimation(WindowManager.TRANSIT_OLD_WALLPAPER_OPEN,
WindowConfiguration.ACTIVITY_TYPE_STANDARD,
new RemoteAnimationAdapter(
// 创建LauncherAnimationRunner 对象
new LauncherAnimationRunner(mHandler, mWallpaperOpenRunner,
false /* startAtFrontOfQueue */),
CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
if (KEYGUARD_ANIMATION.get()) {
mKeyguardGoingAwayRunner = createWallpaperOpenRunner(true /* fromUnlock */);
definition.addRemoteAnimation(
WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
new RemoteAnimationAdapter(
new LauncherAnimationRunner(
mHandler, mKeyguardGoingAwayRunner,
true /* startAtFrontOfQueue */),
CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
}
}
其中的LauncherAnimationRunner继承自RemoteAnimationRunnerCompat
RemoteAnimationRunnerCompat就是远程动画类,路径是:packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
java
public class LauncherAnimationRunner extends RemoteAnimationRunnerCompat
- 触发: 当系统检测到符合注册条件的窗口切换发生时(例如,用户点击图标启动应用,系统准备关闭 Launcher 并打开目标应用),系统不会执行默认的窗口动画,而是会回调 Launcher 中注册的
RemoteAnimationRunnerCompat
或IRemoteTransition
的onAnimationStart
或startAnimation
方法。
java
// Called only in S+ platform
//quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@BinderThread
public void onAnimationStart(
int transit,
RemoteAnimationTarget[] appTargets,
RemoteAnimationTarget[] wallpaperTargets,
RemoteAnimationTarget[] nonAppTargets,
Runnable runnable) {
Runnable r = () -> {
finishExistingAnimation();
mAnimationResult = new AnimationResult(() -> mAnimationResult = null, runnable);
getFactory().onAnimationStart(transit, appTargets, wallpaperTargets, nonAppTargets,
mAnimationResult);
};
if (mStartAtFrontOfQueue) {
postAtFrontOfQueueAsynchronously(mHandler, r);
} else {
postAsyncCallback(mHandler, r);
}
}
- 回调参数: 系统在回调时会提供关键信息:
RemoteAnimationTarget[]
: 一个包含所有参与过渡的窗口(Leash)信息的数组。每个RemoteAnimationTarget
包含窗口的 SurfaceControl (Leash)、初始位置/状态、模式 (MODE_OPENING
或MODE_CLOSING
) 等。IRemoteAnimationFinishedCallback
/IRemoteTransitionFinishedCallback
: 一个回调接口,动画完成后 Launcher 必须调用它来通知系统动画结束,以便系统可以清理资源并完成切换。
上面的onAnimationStart方法中又会去调用其他动画类的onAnimationStart回调方法
java
getFactory().onAnimationStart(transit, appTargets, wallpaperTargets, nonAppTargets,
mAnimationResult);
这里的goFactory得到的是一个接口RemoteAnimationFactory,它的实现类有如下几个:
其中后面三个AppLauncherAnimationRunner、ContainerAnimationRunner、WallpaperOpenLauncherAnimationRunner三个类都是QuickstepTransitionManager的内部动画类
在QuickstepTransitionManager的getActivityLaunchOptions中,会创建AppLauncherAnimationRunner和ContainerAnimationRunner的对象。在option中会附加上这些动画信息,在应用启动后最终回回调这几个类的onAnimationStart方法
java
public ActivityOptionsWrapper getActivityLaunchOptions(View v) {
boolean fromRecents = isLaunchingFromRecents(v, null /* targets */);
RunnableList onEndCallback = new RunnableList();
// Handle the case where an already visible task is launched which results in no transition
TaskRestartedDuringLaunchListener restartedListener =
new TaskRestartedDuringLaunchListener();
restartedListener.register(onEndCallback::executeAllAndDestroy);
onEndCallback.add(restartedListener::unregister);
mAppLaunchRunner = new AppLaunchAnimationRunner(v, onEndCallback);
ItemInfo tag = (ItemInfo) v.getTag();
if (tag != null && tag.shouldUseBackgroundAnimation()) {
ContainerAnimationRunner containerAnimationRunner = ContainerAnimationRunner.from(
v, mLauncher, mStartingWindowListener, onEndCallback);
if (containerAnimationRunner != null) {
mAppLaunchRunner = containerAnimationRunner;
}
}
RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(
mHandler, mAppLaunchRunner, true /* startAtFrontOfQueue */);
// Note that this duration is a guess as we do not know if the animation will be a
// recents launch or not for sure until we know the opening app targets.
long duration = fromRecents
? RECENTS_LAUNCH_DURATION
: APP_LAUNCH_DURATION;
long statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION
- STATUS_BAR_TRANSITION_PRE_DELAY;
ActivityOptions options = ActivityOptions.makeRemoteAnimation(
new RemoteAnimationAdapter(runner, duration, statusBarTransitionDelay),
new RemoteTransition(runner.toRemoteTransition(),
mLauncher.getIApplicationThread(), "QuickstepLaunch"));
return new ActivityOptionsWrapper(options, onEndCallback);
}
-
动画执行:
QuickstepTransitionManager
的onAnimationStart
或startAnimation
方法被触发后,会分析传入的RemoteAnimationTarget[]
来理解当前的过渡场景(哪个应用在打开?哪个在关闭?Launcher 是否参与?)。- 根据场景(启动应用、返回桌面、从概览启动等)和触发源(图标、小部件、返回手势等),它会选择并组合相应的动画逻辑。
- 核心动画构建:
- 窗口动画: 主要通过
RectFSpringAnim
(基于物理的弹簧动画) 或ValueAnimator
来计算窗口 Leash 的变换(位置、缩放、裁剪、圆角、透明度)。这些计算通常涉及到目标视图(如图标)的位置、屏幕尺寸、设备配置等。TaskViewSimulator
虽然主要用于手势导航,但其原理(模拟变换)有时也会被借鉴或用于计算特定场景的窗口目标状态。 - Launcher 内容动画: 同时,它会创建
AnimatorSet
来控制 Launcher 内部 UI 元素的动画(如 Workspace、Hotseat、背景等的淡出、缩放)。这通常通过getLauncherContentAnimator
或StaggeredWorkspaceAnim
,WorkspaceRevealAnim
等辅助类实现。 - 浮动视图动画 (
FloatingIconView
,FloatingWidgetView
): 为了实现图标/小部件"变形"到应用窗口的效果,它会创建一个临时的浮动视图,这个视图的外观在动画过程中会从图标/小部件逐渐过渡到目标窗口的快照或背景色,并跟随窗口动画进行位移和缩放。
- 窗口动画: 主要通过
- 动画同步: 将窗口动画和 Launcher 内容动画组合进一个总的
AnimatorSet
中。 - Surface 应用: 在动画的每一帧 (
ValueAnimator.AnimatorUpdateListener
或RectFSpringAnim.OnUpdateListener
),计算出的窗口变换参数会通过SurfaceControl.Transaction
应用到对应的RemoteAnimationTarget
的 Leash 上。 - 完成回调: 在总动画集的
onAnimationEnd
监听器中,调用系统提供的FinishedCallback
,通知系统动画结束。
-
特殊动画处理:
- 返回桌面 (App Close):
createWallpaperOpenRunner
/WallpaperOpenLauncherAnimationRunner
是处理返回桌面动画的核心。它会找到应用对应的 Launcher 视图(图标或小部件),然后创建动画将应用窗口缩小并过渡到该视图的位置和外观。 - 应用启动 (App Launch):
getActivityLaunchOptions
创建ActivityOptions
并附加一个AppLaunchAnimationRunner
。AppLaunchAnimationRunner
在onAnimationStart
中根据启动源(图标、小部件、概览)选择不同的组合函数 (composeIconLaunchAnimator
,composeWidgetLaunchAnimator
,composeRecentsLaunchAnimator
) 来构建启动动画。 - 解锁动画 (
mKeyguardGoingAwayRunner
): 处理从锁屏解锁直接进入 Launcher 时的特殊动画。 - 返回手势动画 (
LauncherBackAnimationController
): 处理预测性返回手势(Android 14+)中,应用窗口预览和返回到 Home 的动画。
- 返回桌面 (App Close):
在 Launcher3 中的作用:
QuickstepTransitionManager
是实现 Quickstep 核心视觉体验的关键部分。没有它,应用启动和关闭将使用 Android 系统默认的、较为生硬的过渡动画。它的作用体现在:
- 提升视觉流畅度: 提供了高度定制化、与 Launcher UI 紧密结合的过渡动画,使得应用切换感觉更加自然和连贯。
- 实现标志性动画: 负责实现 Quickstep 的标志性动画,如应用图标"展开"成应用窗口、应用窗口"缩小"回图标/小部件。
- 连接系统与 Launcher: 作为 Launcher 和系统窗口管理器之间的桥梁,处理远程动画回调,将系统层面的窗口切换事件转化为 Launcher 内部的 UI 动画。
- 复杂场景协调: 管理涉及多个窗口(应用、壁纸、非应用窗口如 PIP、导航栏)和 Launcher UI 元素的复杂动画同步。
- 性能优化: 通过控制动画时序、使用 Hardware Layer、暂停不必要的视图更新等方式,优化过渡动画的性能。
总结:
QuickstepTransitionManager
是一个复杂但核心的动画管理器。它利用 Android 的远程动画机制,拦截系统默认的窗口切换,并替换为高度定制、与 Launcher UI 深度集成的平滑过渡动画。它通过精确计算窗口变换、同步 Launcher 内容动画、并处理各种特殊场景,极大地提升了 Quickstep 导航的用户体验和视觉效果。理解它的工作原理对于定制 Launcher3 的应用启动/关闭动画至关重要。