我们来深入分析 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
)定制特定的回家动画逻辑。