AOSP Android14 Launcher3——底部任务栏Taskbar详解

前言:Launcher3中底部Taskbar和Navbar,或者说中文里面的术语导航栏,这几个词是很容易让人混淆的地方。本文要介绍的是Taskbar。从字面上意思来看,Taskbar就是任务栏,任务栏是Launcher3中一个重要的组件,尤其是在大屏平板设备上。

Taskbar的UI 形态

Taskbar在Launcher3中到底是指哪部分?

直接上图:


在屏幕底部显示的带有应用图标的部分就是Taskbar中的一部分,从上面LayoutInspector中可以看到,底部高度为161dp的View就是Taskbar。

在Launcher中,Taskbar的视图类是TaskbarDragLayer。

Taskbar有两种状态,一种是上图中完全展开的形态,有个术语叫UnStash状态,还有一种是只有底部一个bar条的形态,这种叫Stash状态。

Taskbar的显示逻辑与流程

核心目标:

Taskbar 旨在为大屏幕设备(平板电脑、折叠屏)提供类似桌面操作系统的体验,在应用运行时提供一个常驻或可按需访问的应用启动器和导航栏。

关键组件和控制器:

  1. TaskbarManager.java: 这是 Taskbar 的全局管理器

    • 职责: 决定是否应该在当前设备和配置下启用 Taskbar。监听设备状态变化(如屏幕旋转、折叠状态、导航模式切换)来判断是否需要创建或销毁 Taskbar UI。
    • 流程:TaskbarManager 确定需要 Taskbar 时(通常在 LauncherActivity 或类似上下文启动时),它会创建 TaskbarActivityContext
  2. TaskbarActivityContext.java: Taskbar 的上下文环境

    • 职责: 这是 Taskbar UI 实际运行的 Context。它负责创建 Taskbar 的主视图(TaskbarView)和 DragLayer (TaskbarDragLayer),并初始化所有的 Taskbar 控制器 (TaskbarControllers)。它还处理与 Launcher Activity 的生命周期绑定、资源获取、权限检查等。
    • 流程:
      • onCreate() 中,它会加载 Taskbar 布局 (R.layout.taskbar)。
      • 创建 TaskbarControllers 实例,该实例会聚合所有其他的子控制器。
      • 调用 TaskbarControllers.init() 来初始化所有子控制器,并建立它们之间的引用。
  3. TaskbarControllers.java: 控制器聚合器

    • 职责: 持有所有其他 Taskbar 子控制器的引用,方便它们之间相互访问和协调。提供一个统一的初始化 (init) 和销毁 (onDestroy) 入口。
    • 流程:init() 中,它会按顺序创建并初始化各个子控制器,如 TaskbarViewControllerTaskbarStashControllerNavbarButtonsViewController 等。
  4. TaskbarView.java: 核心 UI 视图

    • 职责: 继承自 ViewGroup,是容纳 Taskbar 上所有图标(应用、文件夹、预测应用)的容器。它处理图标的布局、添加、移除和更新。
    • 显示:TaskbarActivityContext 创建并添加到其 TaskbarDragLayer 中。
  5. TaskbarViewController.java: TaskbarView 的控制器

    • 职责: 管理 TaskbarView 的内容和视觉状态。
      • 从数据模型(通过 TaskbarModelCallbacks)获取应用列表并绑定到 TaskbarView 上。
      • 处理图标的点击、长按(弹出菜单,通过 TaskbarPopupController)。
      • 控制图标的 Alpha、Scale、TranslationY 等属性,用于配合 TaskbarStashController 实现收起/展开动画。
    • 流程:TaskbarControllers.init() 中被初始化,并获取对 TaskbarView 的引用。监听数据模型变化来更新 UI。
  6. TaskbarStashController.java: 收起/展开逻辑的核心控制器

    • 职责: 这是控制 Taskbar 是否应该显示为完整条、收起成一个细条 (Handle) 或完全隐藏的决策中心和动画协调者
    • 原理 (State Flags): 维护一个整数状态 mState,通过位标志 (FLAG_*) 来记录各种影响 Taskbar 可见性的条件,例如:
      • FLAG_IN_APP: 是否在第三方应用中。
      • FLAG_STASHED_IN_APP_SYSUI: 系统 UI(如通知面板)是否要求收起。
      • FLAG_STASHED_IN_APP_IME: 输入法是否显示。
      • FLAG_IN_STASHED_LAUNCHER_STATE: 当前 Launcher 状态是否要求收起 (如 AllApps)。
      • FLAG_STASHED_IN_APP_AUTO: 是否是瞬态 Taskbar (Transient) 且当前处于自动隐藏状态。
      • FLAG_STASHED_DEVICE_LOCKED: 设备是否锁定。
      • ... 等等。
    • 决策 (mIsStashedPredicate): 通过一个 IntPredicate (一个函数式接口,输入 int 返回 boolean) 来判断当前 mState 的组合是否意味着 Taskbar 应该 处于收起状态 (mIsStashed)。
    • 状态应用 (applyState, createApplyStateAnimator): 当外部事件(如 Launcher 状态改变、系统 UI 状态改变、用户交互等)调用 updateStateForFlag() 更新了 mState 后,会调用 applyState()applyState() 会比较新的预期收起状态 (mIsStashedPredicate.test(newState)) 和当前的视觉状态 (mIsStashed)。
      • 如果状态不一致,则调用 createAnimToIsStashed() 创建一个 AnimatorSet 来驱动 Taskbar UI 元素的动画(背景、图标、Handle 的 Alpha、Scale、Translation)。
      • 动画会平滑地过渡到新的收起/展开状态。
    • 动画类型 (@StashAnimation): 支持多种不同的收起/展开动画效果(TRANSITION_DEFAULT, TRANSITION_HOME_TO_APP, TRANSITION_HANDLE_FADE 等),根据触发场景选择不同的动画插值器和时序。
    • 瞬态 Taskbar (Transient): 对瞬态 Taskbar 有特殊处理逻辑,包括自动隐藏计时器 (mTimeoutAlarm) 和通过 updateAndAnimateTransientTaskbar() 进行显式控制。
  7. StashedHandleViewController.java & StashedHandleView.java: 收起状态 Handle 的控制器和视图

    • 职责:TaskbarStashController 决定收起 Taskbar 时,StashedHandleViewController 负责显示和管理 StashedHandleView(那个白色细条)。它控制 Handle 的 Alpha 和 Scale,实现显示/隐藏以及 Hint 动画(轻微放大提示可以展开)。
  8. TaskbarLauncherStateController.java: Launcher 状态转换器

    • 职责: 监听 Launcher 的状态变化(StateManager.addStateListener),并将 Launcher 状态(如 NORMAL, OVERVIEW, ALL_APPS)转换为 TaskbarStashController 能理解的状态标志 (FLAG_IN_STASHED_LAUNCHER_STATE, FLAG_IN_APP, FLAG_IN_OVERVIEW)。
    • 流程: 当 Launcher 状态切换时,它会调用 TaskbarStashController.updateStateForFlag() 来更新相应的标志,然后触发 TaskbarStashController.applyState() 来应用变化。
  9. TaskbarInsetsController.kt: 窗口 Insets 控制器

    • 职责: 根据 Taskbar 的收起/展开状态和类型(持久/瞬态),计算应该向应用报告的窗口 Insets(底部导航栏区域)。
    • 原理: 当 Taskbar 展开时,报告完整的高度;当收起时,通常报告 mStashedHeight(Handle 的高度),或者在某些特定情况(如持久 Taskbar + IME)下报告 0。它确保应用的内容能够正确地避让 Taskbar。
  10. TaskbarStashViaTouchController.kt: 触摸交互控制器

    • 职责: 处理用户直接在 Stashed Handle 或 Taskbar 背景区域的触摸事件,用于触发/取消瞬态 Taskbar 的自动隐藏计时器,或者启动 Hint 动画。
  11. 其他控制器:

    • NavbarButtonsViewController.java: 管理导航按钮(Back, Home, Recents)的显示、布局和点击事件。
    • TaskbarDragLayerController.java: 管理 Taskbar 的背景、圆角和 Y 轴偏移。
    • TaskbarDragController.java: 处理 Taskbar 内部或涉及 Taskbar 的拖放操作。
    • TaskbarKeyguardController.java: 处理锁屏状态对 Taskbar 的影响。
    • TaskbarPinningController.kt: 处理用户固定/取消固定持久 Taskbar 的设置。
    • TaskbarAutohideSuspendController.java: 管理自动隐藏功能的暂停状态。
    • ... 等等。

加载与显示流程总结:

  1. 启动: LauncherActivity (或其他宿主) 启动。
  2. TaskbarManager 决策: TaskbarManager 判断当前设备配置是否需要 Taskbar。
  3. 创建 Context: 如果需要,TaskbarManager 创建 TaskbarActivityContext
  4. Context 初始化: TaskbarActivityContext 加载布局,创建 TaskbarDragLayerTaskbarView
  5. 控制器聚合: TaskbarActivityContext 创建 TaskbarControllers
  6. 子控制器初始化: TaskbarControllers.init() 逐个创建并初始化所有子控制器 (TaskbarViewController, TaskbarStashController, NavbarButtonsViewController 等),并建立它们之间的引用。
  7. 初始状态设定:
    • TaskbarStashController 根据初始条件(是否 Setup、是否 Phone Mode、是否瞬态、持久化设置等)设置初始的 mState 标志。
    • TaskbarLauncherStateController 获取当前的 Launcher 状态,并更新 TaskbarStashController 的相应标志。
  8. 首次应用状态: TaskbarStashController.applyState(0) 被调用,根据初始的 mState 计算出 Taskbar 应该是收起还是展开,并立即设置 UI 到对应的视觉状态(没有动画)。
  9. Insets 更新: TaskbarInsetsController 根据初始状态计算并向系统报告窗口 Insets。
  10. 数据绑定: TaskbarViewController 开始从模型加载数据并绑定到 TaskbarView 上显示图标。
  11. 事件监听与状态更新:
    • TaskbarLauncherStateController 监听 Launcher 状态变化。
    • TaskbarStashController 监听系统 UI 状态变化 (updateStateForSysuiFlags)。
    • TaskbarKeyguardController 监听锁屏状态。
    • TaskbarPinningController 监听用户 pinning 设置。
    • TaskbarStashViaTouchController 监听触摸事件。
    • 当任何影响可见性的状态发生变化时,对应的控制器会调用 TaskbarStashController.updateStateForFlag()
  12. 动画应用: TaskbarStashController.applyState() 被调用,如果计算出的收起/展开状态与当前视觉状态不同,则创建并启动动画 (mAnimator) 来平滑过渡。
  13. 持续运行: Taskbar 进入运行状态,响应用户交互(点击、长按、拖拽)、系统事件和状态变化,并由 TaskbarStashController 动态调整其可见性。

核心原理:

Taskbar 的核心原理是基于状态的可见性控制动画协调

  • 状态驱动: TaskbarStashController 通过维护一组状态标志 (mState) 来集中管理所有影响 Taskbar 是否应该收起的因素。
  • 解耦: 每个子控制器负责监听和更新自己相关的状态标志,将具体逻辑与最终的可见性决策解耦。
  • 集中决策: TaskbarStashController 根据所有标志的组合,使用 mIsStashedPredicate 做出最终的收起/展开决策。
  • 动画协调: TaskbarStashController 负责创建和管理收起/展开的 AnimatorSet,该动画集会同时驱动 Taskbar 背景、图标和 Handle 等多个 UI 元素的属性变化,实现协调一致的视觉过渡。
  • Insets 同步: TaskbarInsetsController 确保窗口 Insets 与 Taskbar 的状态(以及动画预期)保持一致,让应用能够正确布局。

这种设计使得 Taskbar 能够灵活地响应各种复杂的系统和用户状态变化,同时保持 UI 的流畅性和一致性。

相关推荐
贤泽4 天前
Android15 ContentProvider 深度源码分析(上)
android·aosp
贤泽4 天前
Android15 ContentProvider 深度源码分析(下)
android·aosp
贤泽7 天前
android 15 AOSP Broadcast 广播机制源码分析
android·aosp
奔跑吧 android9 天前
【车载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