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 的应用启动/关闭动画至关重要。

相关推荐
毛豆的毛豆Y5 天前
AOSP Android14 Launcher3——RecentsView最近任务数据加载
aosp·launcher3·android14
毛豆的毛豆Y5 天前
AOSP Android14 Launcher3——点击桌面图标启动应用动画流程
aosp·launcher3·android14
毛豆的毛豆Y6 天前
AOSP Android14 Launcher3——远程窗口动画关键类SurfaceControl详解
aosp·launcher3·android14
毛豆的毛豆Y12 天前
AOSP Android14 Launcher3——底部任务栏Taskbar详解
aosp·launcher3·android14
Mr_Fingerling12 天前
Android12编译x86模拟器报找不到userdata-qemu.img
framework·aosp·android12·x86模拟器
千里马学框架1 个月前
安卓15/aosp15/lineage21使用brunch编译老是报错OOM内存不足
android·车载系统·framework·系统开发·aosp·lineage
hedalei4 个月前
RK3576 Android14编译OTA包提示java.lang.UnsupportedClassVersionError问题
android·android14·rk3576
冬瓜神君4 个月前
Android14 AOSP支持短按关机
android·aosp
Sgq丶5 个月前
Android 13 aosp Launcher 隐藏“壁纸和样式“入口
android·aosp·launcher3