新版负一屏变天了!分享pixel新桌面负一屏技术调研报告

📅 2026/7/1 13:08:37
新版负一屏变天了!分享pixel新桌面负一屏技术调研报告
背景有学员反馈说新版本的pixel负一屏的方案已经不是采用以前的Overlay那种独立Window方式而是使用的独立的Activity方式针对学员提出的这个疑问马哥这边也下载了一个pixel的模拟器进行调研pixel的新版本负一屏方案原理。直观认识主桌面负一屏拖动中间时候调研原理部分层级结构树部分使用dumpsys activity containers和sf等查看负一屏情况DefaultTaskDisplayAreatypeundefinedmodefullscreen override-modefullscreen requested-bounds[0,0][0,0]bounds[0,0][2076,2152]│ ├─Task1typeHOMEmodefullscreen override-modefullscreen requested-bounds[0,0][0,0]bounds[0,0][2076,2152]│ │ └─Task3typeHOMEmodefullscreen override-modeundefined requested-bounds[0,0][0,0]bounds[0,0][2076,2152]│ │ ├─ ActivityRecord{6892885u0 com.google.android.apps.nexuslauncher/.NexusLauncherActivity t3}typeHOMEmodefullscreen override-modeundefined requested-bounds[0,0][0,0]bounds[0,0][2076,2152]│ │ │ └─ 6a55d8e com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivitytypeHOMEmodefullscreen override-modeundefined requested-bounds[0,0][0,0]bounds[0,0][2076,2152]│ │ └─ TaskFragment{b923527modemulti-window}typeHOMEmodeMULTI-WINDOW override-modeMULTI-WINDOW requested-bounds[0,0][0,0]bounds[0,0][2076,2152]│ │ └─ ActivityRecord{184635947u0 com.google.android.googlequicksearchbox/com.google.android.apps.search.googleapp.launcher.minusone.activity.MinusOneActivity t3}typeHOMEmodeMULTI-WINDOW override-modeundefined requested-bounds[0,0][0,0]bounds[0,0][2076,2152]│ │ └─ e843f4 com.google.android.googlequicksearchbox/com.google.android.apps.search.googleapp.launcher.minusone.activity.MinusOneActivitytypeHOMEmodeMULTI-WINDOW override-modeundefined requested-bounds[0,0][0,0]bounds[0,0][2076,2152]上面的相比正常的多了一个 TaskFragment{b923527 modemulti-window}的容器这个是专门装载负一屏的task。关键属性TaskFragment 以WINDOWING_MODE_MULTI_WINDOW创建与 fullscreen 的 Launcher Activity 共存于同一 TaskTaskFragment 的organizerUid10195(com.google.android.apps.nexuslauncher)由 Launcher 控制MinusOneActivity 进程为com.google.android.googlequicksearchbox:googleapp(uid10161)与 Launcher不同进程activity的生命周期部分桌面滑动到负一屏桌面滑动到负一屏时候桌面首先就已经Pasue了然后负一屏进行resume彻底滑到负一屏后桌面进行stop。负一屏滑动回桌面可以看到桌面先调研onStart松手后滑到桌面才是resume然后负一屏的activity就进行stop。三种状态与生命周期1 CLOSED 状态TaskFragment 存在但setHiddentrueMinusOneActivity 未启动或已 stoppedLauncher 独占显示2 OPEN 状态TaskFragmentsetHiddenfalse, MinusOneActivity RESUMEDLauncher Window 仍 VISIBLE 但在 WMS 中mObscuredtrue被 TF 遮挡Launcher Activity 状态为 PAUSEDMinusOneActivity 为mFocusedWindow3 MID-DRAG 状态实验验证以下数据来自拖动到中间位置时的实际 dumpsys 实验WMS 层面 (dumpsys window)属性Launcher (Window #9)MinusOne (Window #8)mViewVisibility0x0 (VISIBLE)0x0 (VISIBLE)mHasSurfacetruetruemObscuredtruefalsemWindowingModefullscreenmulti-windowSurfaceVRI-NexusLauncherActivity#721VRI-MinusOneActivity#758关键发现拖动期间 MinusOne 的 WindowmViewVisibility0x0 (VISIBLE)且mHasSurfacetrue。这与 OPEN 状态一致说明 MinusOne 的 Window 在整个拖动过程中保持可见。Activity 层面 (dumpsys activity)Task{68ab20d #3 typehome} ├─ topResumedActivity MinusOneActivity ← ★ 负一屏是 resumed ├─ TaskFragment{b923527 modemulti-window} │ └─ MinusOneActivity: stateRESUMED │ mWindowingModemulti-window └─ NexusLauncherActivity: statePAUSED mWindowingModefullscreen关键发现拖动过程中 MinusOneActivity 已经处于RESUMED状态Launcher 处于PAUSED。说明一旦开始拖动ACTION_DOWN系统就已经完成了 Activity 生命周期的切换。用户拖动的是已经 RESUME 的 MinusOneActivity 的 Surface 的位置而不是在拖动过程中做 Activity 切换。总结部分Pixel Launcher 的负一屏不是在 Launcher 进程内嵌入一个 View 或 Fragment而是利用 Android 12 的TaskFragment API在 Launcher 的 Task 内创建一个独立的TaskFragment将 Google App (Velvet) 的MinusOneActivity以multi-window模式嵌入其中。两个 Activity 拥有各自独立的 Window 和 Surface在 SurfaceFlinger 层面通过 z-order 叠加显示通过两种不同的偏移机制实现同步滑动偏移目标机制层级Launcher (NexusLauncherActivity)View.setTranslationX()View 层负一屏 (MinusOneActivity)SurfaceControl.Transaction.setMatrix()Surface 层上面就是马哥对于新版本负一屏的初步调研方案后续有时间会进行模仿pixel实现新版本负一屏的demo欢迎相关vip学员找马哥交流实现方案等。