AOSP Android14 Launcher3——动画核心类QuickstepTransitionManager详解

Launcher3中,有一个类在跟桌面相关的各种动画中扮演着非常关键的角色,这个类就是QuickstepTransitionManager。

QuickstepTransitionManager在aosp中的路径为:aosp/packages/apps/Launcher3/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java

接下来我们来深入分析 QuickstepTransitionManager.java 这个类。它是 Quickstep (Launcher3 的手势导航和过渡动画核心实现) 中至关重要的部分,负责管理和协调各种复杂的应用程序启动和关闭过渡动画

核心作用 (Core Role):

QuickstepTransitionManager 的主要职责是定义、注册和执行 当用户在 Launcher 和其他应用程序之间切换时所看到的窗口过渡动画。这包括:

  1. 应用启动动画: 当用户从 Launcher (如点击图标、小部件或从概览启动任务) 启动一个应用程序时,QuickstepTransitionManager 负责创建和运行动画,使得 Launcher 界面元素(如图标、背景、工作区)能够平滑地过渡到应用程序窗口的出现。

  2. 应用关闭动画 (返回桌面): 当用户从一个应用程序通过手势或按键返回到 Launcher (桌面) 时,它负责创建和运行动画,使得应用程序窗口能够平滑地过渡(通常是缩小)到 Launcher 上的对应目标(图标、小部件或屏幕中心),同时 Launcher 界面元素(工作区、背景等)恢复显示。

  3. 概览启动动画: 管理从概览 (RecentsView) 启动任务时的特殊过渡动画。

  4. 特殊场景处理: 处理一些特殊情况下的动画,如从锁屏解锁进入 Launcher、从小部件启动应用、从预测行启动应用等。

  5. 动画参数计算: 计算动画所需的各种参数,如窗口的起始/结束位置、缩放比例、透明度、圆角、裁剪区域等。

  6. 系统动画注册: 向 Android 系统的窗口管理器 (WindowManager) 注册 这些自定义的过渡动画。这通过 RemoteAnimationAdapter (旧版) 或 RemoteTransition (新版 Shell Transitions) 实现,使得系统在进行窗口切换时,能够调用 Launcher 提供的动画逻辑来取代默认的窗口动画。

简单来说,QuickstepTransitionManager 就是 Launcher3 中负责**"让应用打开和关闭看起来很酷很流畅"**的幕后导演。

工作原理 (How it Works):

其工作原理主要基于 Android 提供的远程动画 (Remote Animations / Transitions) 机制:

  1. 注册:
    • 在 Launcher 启动时 (或特定时机),QuickstepTransitionManager 会通过 SystemUiProxy 向系统注册自定义的动画。
    • 它会指定哪些窗口切换场景(由 WindowManager.TransitionTypeTransitionFilter 定义,例如 TRANSIT_OLD_WALLPAPER_OPEN, TRANSIT_OPEN/CLOSE 组合等)应该使用 Launcher 提供的动画逻辑。
    • 注册的核心是一个实现了 RemoteAnimationRunnerCompatIRemoteTransition 接口的对象 (通常是 LauncherAnimationRunner 的实例)。
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
  1. 触发: 当系统检测到符合注册条件的窗口切换发生时(例如,用户点击图标启动应用,系统准备关闭 Launcher 并打开目标应用),系统不会执行默认的窗口动画,而是会回调 Launcher 中注册的 RemoteAnimationRunnerCompatIRemoteTransitiononAnimationStartstartAnimation 方法。
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);
        }
    }
  1. 回调参数: 系统在回调时会提供关键信息:
    • RemoteAnimationTarget[]: 一个包含所有参与过渡的窗口(Leash)信息的数组。每个 RemoteAnimationTarget 包含窗口的 SurfaceControl (Leash)、初始位置/状态、模式 (MODE_OPENINGMODE_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);
    }
  1. 动画执行:

    • QuickstepTransitionManageronAnimationStartstartAnimation 方法被触发后,会分析传入的 RemoteAnimationTarget[] 来理解当前的过渡场景(哪个应用在打开?哪个在关闭?Launcher 是否参与?)。
    • 根据场景(启动应用、返回桌面、从概览启动等)和触发源(图标、小部件、返回手势等),它会选择并组合相应的动画逻辑。
    • 核心动画构建:
      • 窗口动画: 主要通过 RectFSpringAnim (基于物理的弹簧动画) 或 ValueAnimator 来计算窗口 Leash 的变换(位置、缩放、裁剪、圆角、透明度)。这些计算通常涉及到目标视图(如图标)的位置、屏幕尺寸、设备配置等。TaskViewSimulator 虽然主要用于手势导航,但其原理(模拟变换)有时也会被借鉴或用于计算特定场景的窗口目标状态。
      • Launcher 内容动画: 同时,它会创建 AnimatorSet 来控制 Launcher 内部 UI 元素的动画(如 Workspace、Hotseat、背景等的淡出、缩放)。这通常通过 getLauncherContentAnimatorStaggeredWorkspaceAnim, WorkspaceRevealAnim 等辅助类实现。
      • 浮动视图动画 (FloatingIconView, FloatingWidgetView): 为了实现图标/小部件"变形"到应用窗口的效果,它会创建一个临时的浮动视图,这个视图的外观在动画过程中会从图标/小部件逐渐过渡到目标窗口的快照或背景色,并跟随窗口动画进行位移和缩放。
    • 动画同步: 将窗口动画和 Launcher 内容动画组合进一个总的 AnimatorSet 中。
    • Surface 应用: 在动画的每一帧 (ValueAnimator.AnimatorUpdateListenerRectFSpringAnim.OnUpdateListener),计算出的窗口变换参数会通过 SurfaceControl.Transaction 应用到对应的 RemoteAnimationTarget 的 Leash 上。
    • 完成回调: 在总动画集的 onAnimationEnd 监听器中,调用系统提供的 FinishedCallback,通知系统动画结束。
  2. 特殊动画处理:

    • 返回桌面 (App Close): createWallpaperOpenRunner / WallpaperOpenLauncherAnimationRunner 是处理返回桌面动画的核心。它会找到应用对应的 Launcher 视图(图标或小部件),然后创建动画将应用窗口缩小并过渡到该视图的位置和外观。
    • 应用启动 (App Launch): getActivityLaunchOptions 创建 ActivityOptions 并附加一个 AppLaunchAnimationRunnerAppLaunchAnimationRunneronAnimationStart 中根据启动源(图标、小部件、概览)选择不同的组合函数 (composeIconLaunchAnimator, composeWidgetLaunchAnimator, composeRecentsLaunchAnimator) 来构建启动动画。
    • 解锁动画 (mKeyguardGoingAwayRunner): 处理从锁屏解锁直接进入 Launcher 时的特殊动画。
    • 返回手势动画 (LauncherBackAnimationController): 处理预测性返回手势(Android 14+)中,应用窗口预览和返回到 Home 的动画。

在 Launcher3 中的作用:

QuickstepTransitionManager 是实现 Quickstep 核心视觉体验的关键部分。没有它,应用启动和关闭将使用 Android 系统默认的、较为生硬的过渡动画。它的作用体现在:

  • 提升视觉流畅度: 提供了高度定制化、与 Launcher UI 紧密结合的过渡动画,使得应用切换感觉更加自然和连贯。
  • 实现标志性动画: 负责实现 Quickstep 的标志性动画,如应用图标"展开"成应用窗口、应用窗口"缩小"回图标/小部件。
  • 连接系统与 Launcher: 作为 Launcher 和系统窗口管理器之间的桥梁,处理远程动画回调,将系统层面的窗口切换事件转化为 Launcher 内部的 UI 动画。
  • 复杂场景协调: 管理涉及多个窗口(应用、壁纸、非应用窗口如 PIP、导航栏)和 Launcher UI 元素的复杂动画同步。
  • 性能优化: 通过控制动画时序、使用 Hardware Layer、暂停不必要的视图更新等方式,优化过渡动画的性能。

总结:

QuickstepTransitionManager 是一个复杂但核心的动画管理器。它利用 Android 的远程动画机制,拦截系统默认的窗口切换,并替换为高度定制、与 Launcher UI 深度集成的平滑过渡动画。它通过精确计算窗口变换、同步 Launcher 内容动画、并处理各种特殊场景,极大地提升了 Quickstep 导航的用户体验和视觉效果。理解它的工作原理对于定制 Launcher3 的应用启动/关闭动画至关重要。

相关推荐
贤泽3 天前
Android15 ContentProvider 深度源码分析(上)
android·aosp
贤泽3 天前
Android15 ContentProvider 深度源码分析(下)
android·aosp
贤泽6 天前
android 15 AOSP Broadcast 广播机制源码分析
android·aosp
奔跑吧 android8 天前
【车载Audio】【AudioHal 07】【高通音频架构】【从逻辑策略到物理执行】
音视频·audio·aosp·android15·8295·音频子系统
42nf1 个月前
Android Launcher3添加负一屏
android·launcher3·android负一屏
不会Android的潘潘1 个月前
受限系统环境下的 WebView 能力演进:车载平台 Web 渲染异常的根因分析与优化实践
android·java·前端·aosp
奔跑吧 android1 个月前
【车载audio开发】【Qualcomm PAL 详解 6】【PAL 总体架构与模块交互指南】
audio·aosp·pal·高通音频框架·8155·8295
奔跑吧 android1 个月前
【车载audio开发】【Qualcomm PAL 详解 4】【Session 模块 介绍】
audio·aosp·高通·车载音频
不会Android的潘潘1 个月前
adb指令扩展方案
android·adb·aosp
Just_Paranoid2 个月前
【AOSP】Android Dump 信息快速定位方法
android·adb·framework·service·aosp·dumpsys