我们来深入分析 quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java 这个非常核心且复杂的类。
1. 核心作用 (Core Role):
AbsSwipeUpHandler 是 Quickstep (Launcher3 的手势导航实现) 中处理从屏幕底部上滑手势的核心逻辑抽象基类。它负责管理从手势开始到结束的整个流程,包括:
- 手势识别与处理: 接收原始触摸事件,计算滑动距离、速度和方向。
- 窗口动画控制: 连接并控制由 SystemUI 提供的
RecentsAnimationController,通过操作应用窗口和 Launcher 窗口的 Surface (Leash),实现平滑的过渡动画(应用 <-> Launcher/概览)。 - 界面状态同步: 协调 Launcher UI 元素(如 Workspace、Hotseat、RecentsView)的状态和动画,使其与手势进度和窗口动画保持同步。
- 目标状态决策: 根据手势的速度、距离、暂停状态以及用户在 RecentsView 中的交互,计算手势的最终目标(
GestureEndTarget):返回桌面 (HOME)、进入概览/最近任务 (RECENTS)、切换到上一个应用 (LAST_TASK)、切换到新任务 (NEW_TASK) 或进入所有应用列表 (ALL_APPS)。 - 动画执行与收尾: 启动并管理过渡到最终目标状态的动画,并在动画结束后释放资源、完成任务切换或返回桌面。
- 处理特殊情况: 如 PiP (画中画) 窗口的特殊动画、分屏模式、Taskbar 交互等。
简单来说,它是连接用户上滑手势输入、系统窗口动画控制以及 Launcher UI 状态变化的总指挥。
2. 如何协调其他类 (Coordination):
AbsSwipeUpHandler 像一个交响乐指挥,协调多个组件共同完成复杂的动画和状态切换:
GestureState:- 提供者: 外部(如
TouchInteractionService)创建并传入。 - 交互:
AbsSwipeUpHandler从GestureState读取手势信息(起始点、当前运行任务、速度、是否暂停等),并将计算出的最终目标 (endTarget) 写回GestureState。
- 提供者: 外部(如
RecentsAnimationController&RecentsAnimationTargets:- 提供者: 由 SystemUI (WindowManager) 在手势开始时通过
onRecentsAnimationStart回调提供。 - 交互:
AbsSwipeUpHandler使用RecentsAnimationController来:- 获取和控制应用/Launcher 窗口的 Surface Leash。
- 截取任务快照 (
screenshotTask)。 - 设置 SystemUI 标志(如状态栏/导航栏外观)。
- 最终结束动画 (
finish()),将控制权交还给系统。
RecentsAnimationTargets提供了动画目标的详细信息(如 TaskInfo, Leash, 初始位置等)。
- 提供者: 由 SystemUI (WindowManager) 在手势开始时通过
TaskViewSimulator&RemoteTargetHandle&RemoteTargetGluer:- 交互:
AbsSwipeUpHandler通过RemoteTargetGluer将RecentsAnimationTargets分配给一个或多个RemoteTargetHandle。每个RemoteTargetHandle包含一个TaskViewSimulator。 TaskViewSimulator至关重要,它负责计算应用窗口 Leash 的变换(Translation, Scale, Alpha, Crop, Corner Radius)。AbsSwipeUpHandler在applyScrollAndTransform方法中,根据当前手势进度 (mCurrentShift.value) 和RecentsView的滚动偏移,更新TaskViewSimulator的状态,并应用这些变换到实际的 Surface Leash 上。
- 交互:
StatefulActivity(e.g.,QuickstepLauncher) &BaseActivityInterface:- 交互: 通过
mActivityInterface与 Launcher Activity 交互:- 获取 Activity 实例 (
getCreatedActivity())。 - 获取核心 UI 组件,特别是
RecentsView(getOverviewPanel())。 - 准备 Recents UI (
prepareRecentsUI),这通常会返回一个AnimationFactory,用于创建 Launcher 内部元素的动画控制器 (mLauncherTransitionController)。 - 通知 Activity 手势结束并即将返回桌面 (
onSwipeUpToHomeComplete) 或切换任务失败 (onLaunchTaskFailed)。 - 获取
DeviceProfile和其他配置信息。
- 获取 Activity 实例 (
- 交互: 通过
RecentsView(e.g.,LauncherRecentsView):- 交互:
- 在手势开始时通知
RecentsView(onGestureAnimationStart),让它可以准备任务卡片。 - 链接滚动事件 (
linkRecentsViewScroll,mOnRecentsScrollListener):当RecentsView滚动时,会触发onRecentsViewScroll,进而调用applyScrollAndTransform来更新应用窗口的位置,实现窗口跟随卡片滚动的效果。 - 获取当前/目标页面 (
getCurrentPage,getNextPage) 和对应的TaskView,用于判断手势目标和启动任务。 - 在手势结束动画开始时,让
RecentsView参与动画 (onPrepareGestureEndAnimation)。 - 在手势结束动画完成后,通知
RecentsView(onSwipeUpAnimationSuccess或onGestureAnimationEnd)。 - 更新任务缩略图 (
updateThumbnail)。
- 在手势开始时通知
- 交互:
MultiStateCallback(mStateCallback):- 作用: 这是
AbsSwipeUpHandler内部管理异步流程的关键机制。手势涉及多个异步事件(Launcher 启动、绘制完成、动画控制器接收、截图完成、手势完成等)。mStateCallback定义了一系列状态标志 (STATE_*)。 - 交互: 通过
mStateCallback.setStateOnUiThread()设置状态,通过mStateCallback.runOnceAtState(STATE_FLAGS, runnable)注册回调。只有当所有指定的状态标志位都变为 1 时,对应的runnable才会被执行。这确保了操作在正确的时机发生,避免了复杂的嵌套回调和竞态条件。
- 作用: 这是
AnimatorControllerWithResistance(mLauncherTransitionController):- 作用: 控制 Launcher 内部 UI 元素的动画(例如 Hotseat 的淡出、Workspace 的缩放)。
- 交互: 由
AnimationFactory(通过mActivityInterface.prepareRecentsUI获得) 创建。AbsSwipeUpHandler在onCurrentShiftUpdated中根据手势进度 (mCurrentShift.value) 更新这个控制器的进度,驱动 Launcher UI 的过渡效果。
HomeAnimationFactory(由子类实现):- 作用: 定义了当手势目标是
HOME时,窗口如何具体地动画到桌面上(例如,缩小到图标、缩小到小部件、或者仅仅是淡出)。 - 交互:
AbsSwipeUpHandler在确定目标是HOME时,会调用子类实现的createHomeAnimationFactory来获取具体的动画逻辑,并执行它。
- 作用: 定义了当手势目标是
InputConsumerProxy:- 作用: 在手势进行到特定阶段(例如,确定要进入 Launcher 状态时)启用,拦截原本会传递给下方应用窗口的触摸事件,确保手势能继续控制 Launcher UI。
3. 手势与最近任务动画流程示例 (Simplified Flow):
- 手势开始: 用户从底部上滑。
TouchInteractionService检测到手势,创建AbsSwipeUpHandler实例。 - 系统动画启动: SystemUI 启动 Recents 动画,调用
onRecentsAnimationStart,提供controller和targets。 - Launcher 准备:
AbsSwipeUpHandler通过mActivityInitListener等待 Launcher Activity (mActivity) 准备好。onActivityInit获取mRecentsView引用。prepareRecentsUI被调用,mLauncherTransitionController被创建。 - 手势进行中:
- 用户手指移动,
updateDisplacement计算出手势进度mCurrentShift.value。 onCurrentShiftUpdated被调用。applyScrollAndTransform使用TaskViewSimulator更新应用窗口 Leash 的变换(缩放、平移等)。mLauncherTransitionController.setProgress更新 Launcher 内部 UI 动画。- 如果用户在
RecentsView上左右滑动,onRecentsViewScroll会触发,同样调用applyScrollAndTransform使窗口跟随移动。
- 用户手指移动,
- 手势结束: 用户抬起手指。
onGestureEnded被调用。 - 目标计算:
calculateEndTarget根据速度、位置、是否暂停等因素,决定最终去向(HOME,RECENTS,LAST_TASK等)。 - 结束动画:
handleNormalGestureEnd->animateToProgressInternal启动收尾动画。- 去 HOME: 调用
createHomeAnimationFactory,启动特定的回家动画(可能是RectFSpringAnim驱动窗口缩小到图标/小部件)。 - 去 RECENTS/LAST_TASK: 启动
ValueAnimator平滑过渡mCurrentShift.value到 0 或 1,同时可能驱动RecentsView滚动到目标页面。
- 动画完成 & 状态同步: 动画结束监听器触发
onSettledOnEndTarget。 - 最终操作: 根据
endTarget:- HOME/RECENTS: 调用
mRecentsAnimationController.finish(true/false, ...)通知系统结束动画,释放 Leash 控制。 - LAST_TASK: 调用
mRecentsAnimationController.finish(false, ...)恢复上一个任务。 - NEW_TASK: 调用
startNewTask启动RecentsView中选中的任务。
- HOME/RECENTS: 调用
- 清理:
reset被调用,清理状态和监听器,准备下一次手势。
AbsSwipeUpHandler 通过精密的事件监听、状态管理和对系统动画 API 及 Launcher 内部组件的协调,实现了复杂而流畅的手势导航体验。它的抽象设计允许子类(如 LauncherSwipeHandlerV2)定制特定的回家动画逻辑。
