
SystemUI 是 Android 进程,负责当前获得焦点的应用之外屏幕上几乎所有可见内容。它绘制状态栏、通知面板、快捷设置、锁屏、导航栏、音量对话框、电源菜单、截屏界面以及最近应用浮层。它是一个独立 APK,以系统持久化服务身份运行,UID 为android.uid.systemui;如果该进程被杀死,框架会通过 RescueParty 自动将其重启。SystemUI 是 AOSP 中规模最大的单个软件包之一。其源码目录在frameworks/base/packages/SystemUI/src/com/android/systemui/下包含超过 180 个子包,覆盖无障碍到 wmshell 等多个领域。该代码库正在进行为期多年的迁移工作:旧式的单大类上帝对象正在被分层架构取代(大致为 MVVM/MVI 架构:数据仓库 → 领域交互器 → UI 视图模型),同时引入 Dagger 依赖注入、Kotlin 协程与 Jetpack Compose。Android 17 进一步推进了这项迁移。本章主要介绍两项结构性变更:Scene 框架(flexiglass):基于 Compose 的SceneTransitionLayout,用声明式场景(锁屏、通知面板、快捷设置、隐藏状态)与浮层(密码输入界面、通知面板、快捷设置面板)替换了手写的NotificationPanelViewController/CentralSurfacesImpl滑动与状态逻辑。该特性由SceneContainerFlag开关控制。pods / 模块化改造:SystemUI 包内新增顶层pods/目录,将具备完整自包含能力的功能模块(场景、通知面板、快捷设置、状态栏、通知、亮度、用户等)拆分出来,成为可独立编译的 Soong 模块。迁移到pods/下的代码仍然保留com.android.systemui.*包名,例如Scenes类可以从src/移动至pods/scene/src/api/,其全限定类名不会发生变化。本章会详细剖析每一个主要子系统,跟踪从进程启动到各个可视界面的完整代码路径,并在对应小节中融入 Android 17 带来的改动。48.1 SystemUI 架构48.1.1 进程启动SystemUI 在清单文件中声明android:sharedUserId="android.uid.systemui"以及coreApp="true":!-- frameworks/base/packages/SystemUI/AndroidManifest.xml -- manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.systemui" android:sharedUserId="android.uid.systemui" coreApp="true"当system_server调用IStatusBarService.registerStatusBar()时,该进程启动。入口点是普通 Android 服务SystemUIService:// frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java public class SystemUIService extends Service { @Inject public SystemUIService( @Main Handler mainHandler, DumpHandler dumpHandler, BroadcastDispatcher broadcastDispatcher, LogBufferEulogizer logBufferEulogizer, LogBufferFreezer logBufferFreezer, BatteryStateNotifier batteryStateNotifier, UncaughtExceptionPreHandlerManager uncaughtExceptionPreHandlerManager) { // ... } @Override public void onCreate() { super.onCreate(); // Start all of SystemUI ((SystemUIApplication) getApplication()).startSystemUserServicesIfNeeded(); // ... } }Application 的子类为SystemUIApplicationImpl。它的onCreate方法初始化 Dagger 依赖图,并注册监听BOOT_COMPLETED广播:// frameworks/base/packages/SystemUI/src/com/android/systemui/application/impl/ // SystemUIApplicationImpl.java public class SystemUIApplicationImpl extends SystemUIApplication implements ApplicationContextInitializer, HasWMComponent { @Override public void onCreate() { super.onCreate(); TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming", Trace.TRACE_TAG_APP); log.traceBegin("DependencyInjection"); mInitializer = mContextAvailableCallback.onContextAvailable(this); mSysUIComponent = mInitializer.getSysUIComponent(); mBootCompleteCache = mSysUIComponent.provideBootCacheImpl(); log.traceEnd(); // ... } }48.1.2 Dagger 依赖注入SystemUI 使用三层 Dagger 组件层级:GlobalRootComponent是顶层组件,绑定应用上下文,对外暴露SysUIComponent.Builder:// frameworks/base/packages/SystemUI/src/com/android/systemui/dagger/ // GlobalRootComponent.java public interface GlobalRootComponent { interface Builder { @BindsInstance Builder context(Context context); @BindsInstance Builder instrumentationTest(@InstrumentationTest boolean test); GlobalRootComponent build(); } WMComponent.Builder getWMComponentBuilder(); SysUIComponent.Builder getSysUIComponent(); InitializationChecker getInitializationChecker(); @Main Looper getMainLooper(); }SysUIComponent是主要子组件,绝大多数 SystemUI 单例都在此创建,它导入大量 Dagger 模块:// frameworks/base/packages/SystemUI/src/com/android/systemui/dagger/ // SysUIComponent.java @SysUISingleton @Subcomponent(modules = { DefaultComponentBinder.class, DependencyProvider.class, MultiUserUtilsModule.class, NotificationInsetsModule.class, QsFrameTranslateModule.class, ReferenceSystemUIModule.class, StartControlsStartableModule.class, StartBinderLoggerModule.class, SystemUIModule.class, SystemUICoreStartableModule.class, WallpaperModule.class}) public interface SysUIComponent { // ... MapClass?, ProviderCoreStartable getStartables(); @PerUser MapClass?, ProviderCoreStartable getPerUserStartables(); }构建器接收来自WMComponent的 Shell 接口,例如画中画、分屏、气泡、Shell 转场动画。SystemUI 正是通过这种方式和窗口管理器 Shell 进程完成集成。SystemUIInitializer负责编排 Dagger 依赖图的构建:// frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java public abstract class SystemUIInitializer { public void init(boolean fromTest) throws ExecutionException, InterruptedException { mRootComponent = getGlobalRootComponentBuilder() .context(mContext) .instrumentationTest(fromTest) .build(); // Stand up WMComponent setupWmComponent(mContext); // Build SysUI, injecting Shell interfaces SysUIComponent.Builder builder = mRootComponent.getSysUIComponent(); builder = prepareSysUIComponentBuilder(builder, mWMComponent) .setShell(mWMComponent.getShell()) .setPip(mWMComponent.getPip()) .setSplitScreen(mWMComponent.getSplitScreen()) // ... more shell bindings ; mSysUIComponent = builder.build(); Dependency dependency = mSysUIComponent.createDependency(); dependency.start(); } }48.1.3 CoreStartable —— 服务生命周期SystemUI 每一项主要功能都实现CoreStartable接口。该接口定义由 Application 驱动的生命周期:start():按拓扑排序顺序,仅调用一次onBootCompleted()isDumpCritical():是否纳入 bugreport 的 CRITICAL 输出片段dump():供adb shell dumpsys使用CoreStartable通过 Dagger 多绑定机制注册到 Dagger 模块:// frameworks/base/packages/SystemUI/src/com/android/systemui/dagger/ // SystemUICoreStartableModule.kt @Module abstract class SystemUICoreStartableModule { @Binds @IntoMap @ClassKey(KeyguardViewMediator::class) abstract fun bindKeyguardViewMediator(sysui: KeyguardViewMediator): CoreStartable @Binds @IntoMap @ClassKey(GlobalActionsComponent::class) abstract fun bindGlobalActionsComponent(sysui: GlobalActionsComponent): CoreStartable @Binds @IntoMap @ClassKey(WMShell::class) abstract fun bindWMShell(sysui: WMShell): CoreStartable // ... 30+ more bindings }Application 执行拓扑排序启动,启动顺序严格遵循依赖关系:java运行// SystemUIApplicationImpl.java -- topological start loop boolean startedAny = false; ArrayDequeMap.EntryClass?, ProviderCoreStartable queue; ArrayDequeMap.EntryClass?, ProviderCoreStartable nextQueue = new ArrayDeque(startables.entrySet()); do { startedAny = false; queue = nextQueue; nextQueue = new ArrayDeque(startables.size()); while (!queue.isEmpty()) { Map.EntryClass?, ProviderCoreStartable entry = queue.removeFirst(); Class? cls = entry.getKey(); SetClass? extends CoreStartable deps = mSysUIComponent.getStartableDependencies().get(cls); if (deps == null || startedStartables.containsAll(deps)) { mServices[i] = startStartable(clsName, entry.getValue()); startedStartables.add(cls); startedAny = true; } else { nextQueue.add(entry); } } } while (startedAny !nextQueue.isEmpty());如果某个 startable 的依赖无法满足,进程会抛出RuntimeException,输出缺失依赖的详细信息。48.1.4 插件系统SystemUI 通过插件架构支持运行时扩展。插件是实现插件源码集中定义接口的 APK:frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/ qs/QSTile.java qs/QSFactory.java qs/QS.java GlobalActions.java VolumeDialogController.java ...ExtensionController发现并加载插件,GlobalActionsComponent是典型示例:// frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/ // GlobalActionsComponent.java @Override public void start() { mExtension = mExtensionController.newExtension(GlobalActions.class) .withPlugin(GlobalActions.class) .withDefault(mGlobalActionsProvider::get) .withCallback(this::onExtensionCallback) .build(); mPlugin = mExtension.get(); }OEM 可以使用平台签名的插件 APK 替换默认电源菜单、音量对话框或者快捷设置磁贴。48.1.5 功能标记SystemUI 使用 Android 的 aconfig 标记系统做功能开关。标记定义存放位置:frameworks/base/packages/SystemUI/aconfig/业务代码通过自动生成的访问器读取标记:import com.android.systemui.Flags; if (Flags.predictiveBackAnimateShade()) { // new behavior }快捷设置流水线拥有独立标记仓库:// frameworks/base/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/ // QSPipelineFlagsRepository.kt @SysUISingleton class QSPipelineFlagsRepository @Inject constructor() { val tilesEnabled: Boolean get() = AconfigFlags.qsNewTiles() }48.1.6 目录结构下面是frameworks/base/packages/SystemUI/src/com/android/systemui/下 180 余个子包的精简列表:accessibility/—— 放大手势、悬浮菜单activity/—— Activity 生命周期工具类ambient/—— 息屏显示authentication/—— 设备认证领域层back/—— 预测返回手势battery/—— 电池状态biometrics/—— 指纹、人脸、屏下指纹bluetooth/—— 蓝牙快捷磁贴数据bouncer/—— 锁屏密码输入界面(MVI 架构)brightness/—— 亮度滑块camera/—— 相机使用状态追踪charging/—— 充电动画classifier/—— 触摸误触判定clipboardoverlay/—— 剪贴板预览浮层communal/—— 可一瞥组件模式controls/—— 设备控制(智能家居)dagger/—— DI 组件与模块demomode/—— 截图演示模式display/—— 显示管理doze/—— Doze/AOD 息屏dreams/—— 屏保(Daydream)flags/—— 功能标记基础设施fragments/—— Fragment 宿主globalactions/—— 电源菜单keyguard/—— 锁屏media/—— 媒体控制、输出选择器navigationbar/—— 导航栏与手势导航notifications/—— 通知处理流水线plugins/—— 插件框架power/—— 电源领域层privacy/—— 隐私指示器qs/—— 快捷设置recents/—— 最近任务scene/—— Scene 容器(下一代 UI)screenshot/—— 截屏捕获与编辑shade/—— 通知下拉面板statusbar/—— 状态栏、图标、策略volume/—— 音量对话框wallpapers/—— 壁纸管理wmshell/—— WM Shell 集成除src/目录外,Android 17 在 SystemUI 包顶层新增同级pods/目录:frameworks/base/packages/SystemUI/pods/。每一个 pod 是自包含功能模块,拥有独立 Soong 编译目标,包含src/、ui/、测试源码,例如pods/scene/、pods/shade/、pods/qs/、pods/statusbar/、pods/notifications/、pods/brightness/、pods/user/等。迁移到 pod 中的代码保持原有com.android.systemui.*包名,对调用方完全透明。例如核心Scenes以及场景标识定义现在存放于frameworks/base/packages/SystemUI/pods/scene/src/api/shared/model/Scenes.kt,包名为com.android.systemui.scene.shared.model;而 Scene 框架其余交互器、startable、视图模型仍保留在src/com/android/systemui/scene/。当本章给出的路径在src/下找不到时,请去对应的pods/模块查找。SystemUI 进程组件关系:48.2 状态栏状态栏是屏幕顶部窄条,展示时钟、通知图标、电池电量、信号强度以及各类系统状态图标。它是 SystemUI 启动阶段最早创建的可视化组件之一。48.2.1 CentralSurfaces —— 总协调器CentralSurfaces是接口,继承Dumpable、LifecycleOwner、CoreStartable。实现类CentralSurfacesImpl代码约 2800 行(早期版本超过 3200 行,逻辑持续拆分),历史上作为状态栏、通知面板、锁屏等模块的中央协调器。// frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/ // CentralSurfaces.java public interface CentralSurfaces extends Dumpable, LifecycleOwner, CoreStartable { String TAG = "CentralSurfaces"; boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true; long LAUNCH_TRANSITION_TIMEOUT_MS = 5000; // ... }CentralSurfacesImpl构造函数依赖几乎所有 SystemUI 组件,负责:状态栏窗口创建与位置设置通知面板展开收起锁屏 / 密码输入界面转场状态栏图标明暗色调生物识别解锁动画锁屏媒体封面演示模式该类正在被逐步拆解。新代码应当依赖粒度更小的接口(如ShadeController、ShadeViewController、KeyguardStateController),而不要直接依赖CentralSurfaces。48.2.2 StatusBarWindowController状态栏属于窗口类型WindowManager.LayoutParams.TYPE_STATUS_BAR。窗口管理逻辑封装在StatusBarWindowControllerImpl:// frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/window/ // StatusBarWindowControllerImpl.java public class StatusBarWindowControllerImpl implements StatusBarWindowController { // Window type, insets configuration, cutout handling }状态栏窗口关键属性:属性值窗口类型TYPE_STATUS_BAR像素格式PixelFormat.TRANSLUCENT挖孔模式LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS对齐方式Gravity.TOP窗口标记FLAG_NOT_FOCUSABLE, FLAG_TOUCHABLE_WHEN_WAKING控制器处理屏幕挖孔、刘海,配置InsetsFrameProvider,使状态栏参与 Inset 系统。应用程序可以收到对应状态栏高度的statusBars()insets。48.2.3 主页状态栏流水线旧版本中,收起状态的状态栏 UI 内容由单一CollapsedStatusBarFragment驱动,该 Fragment 加载R.layout.status_bar布局,同时实现多个回调接口。Android 17 完成了对这个巨型 Fragment 的拆解,重构为主页状态栏 MVVM 流水线,不再使用 Fragment 子类驱动状态栏。根布局R.layout.status_bar对应的PhoneStatusBarView通过绑定器和视图模型完成绑定。frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/ viewmodel/HomeStatusBarViewModel.kt -- 可观察状态栏状态 binder/HomeStatusBarViewBinder.kt -- 将视图绑定至视图模型 domain/interactor/HomeStatusBarInteractor.kt每块显示区域的窗口作用域由HomeStatusBarComponent提供,它是 Dagger 的@Subcomponent;每次创建PhoneStatusBarView都会重新生成该子组件,也就是过去的StatusBarFragmentComponent。// frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/ // fragment/dagger/HomeStatusBarComponent.java @Subcomponent(modules = {HomeStatusBarModule.class}) public interface HomeStatusBarComponent { @Subcomponent.Factory interface Factory { HomeStatusBarComponent create( @BindsInstance @RootView PhoneStatusBarView phoneStatusBarView, @BindsInstance StatusBarWindowController statusBarWindowController); } }视图模型整合旧 Fragment 监听的各类信号,现在全部以 Flow 流形式提供:来自system_server的 disable 标记,控制图标隐藏状态栏状态切换(SHADE、KEYGUARD、SHADE_LOCKED)系统事件动画:隐私指示器、通话、录屏、媒体投射动画 Chip(statusbar/chips/包)通知面板展开:面板下拉时图标淡出当 Scene 框架开关SceneContainerFlag开启时,状态栏可以由 Compose 根组件statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt承载,不再使用 View 层级布局。48.2.4 PhoneStatusBarViewPhoneStatusBarView是收起状态状态栏的根 View:// frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/ // PhoneStatusBarView.java public class PhoneStatusBarView extends FrameLayout { // Touch handling, cutout/insets, system-event animation hooks }视图控制器PhoneStatusBarViewController(现已改为 Kotlin)处理触摸事件,驱动HomeStatusBarViewBinder。明暗图标色调由LightBarController通过区域采样判断状态栏下方壁纸或者 App 内容的明暗来计算。48.2.5 状态栏图标流水线状态栏图标经过多阶段流水线流转:StatusBarManager→setIcon()→CommandQueue→StatusBarIconController→DarkIconManager→StatusBarIconView→NotificationIconContainerStatusBarIconController维护图标列表以及可见性。DarkIconManager负责着色:深色背景显示白色图标,浅色背景显示深色图标。LightBarController读取状态栏下层窗口的 Drawable 内容,计算色调切换边界。48.2.6 状态栏状态状态栏存在多个逻辑状态,由StatusBarStateControllerImpl管理:// frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ // StatusBarState.java public class StatusBarState { public static final int SHADE = 0; // 正常已解锁 public static final int KEYGUARD = 1; // 锁屏 public static final int SHADE_LOCKED = 2; // 锁屏状态下拉通知面板 }状态之间的切换会驱动 SystemUI 各处动画。状态控制器向所有注册的StateListener广播变更。48.2.7 隐私指示器与位置指示器隐私指示器是状态栏末端出现的 Chip 组件,当 App 使用相机、麦克风、位置信息时显示。相关代码位于frameworks/base/packages/SystemUI/src/com/android/systemui/privacy/。AppOpsPrivacyItemMonitor监听 AppOps 权限,将活跃访问转换为PrivacyItem对象;PrivacyItemController维护当前列表,供给OngoingPrivacyChip渲染。每一条条目拥有PrivacyType(定义在PrivacyItem.kt):TYPE_CAMERA、TYPE_MICROPHONE、TYPE_LOCATION、TYPE_MEDIA_PROJECTION,每类拥有独立图标与文字。展示哪些条目由privacy命名空间下两个DeviceConfig标记控制,由PrivacyConfig读取。PROPERTY_MIC_CAMERA_ENABLED控制相机麦克风,位置指示器走独立分支。AppOpsPrivacyItemMonitor区分两类权限集合:OPS_MIC_CAMERA对应相机与录音,OPS_LOCATION对应OP_FINE_LOCATION。当locationAvailable关闭时,位置权限会被过滤,不会生成PrivacyItem。Android 17 通过 aconfig 标记android.location.flags.location_indicators_enabled重构位置指示器逻辑,配套标记有location_indicators_animation、location_indicators_outline。PrivacyConfig.locationAvailable从该标记初始化,标记总开关控制指示器是否启用。标记开启后,位置访问生成独立样式 Chip,不再复用相机麦克风样式。PrivacyConfig.privacyItemsAreLocationOnly()判断当前是否全部条目均为位置类型;若是,getPrivacyColor()返回R.color.privacy_chip_location_only_background。当location_indicators_outline打开,getPrivacyOutlineColor()、getPrivacyOutlineStroke()为纯位置 Chip 增加 1px 描边,相机麦克风 Chip 则使用填充背景。该标记同时修改位置 Chip 驻留时长。PrivacyItemController.processNewList()中,纯位置条目保持TIME_TO_HOLD_INDICATORS_FOR_LOCATION(10 秒),其余权限使用TIME_TO_HOLD_INDICATORS(5 秒)。短暂的位置读取也可以保证足够时长让用户察觉。点击 Chip 会打开PrivacyDialogControllerV2隐私弹窗,展示哪些应用正在使用对应权限。48.3 通知面板通知面板是从屏幕顶部向下滑出的面板,展示通知与快捷设置,是 Android 中最复杂 UI 组件之一。48.3.1 窗口配置通知面板使用独立窗口,窗口类型TYPE_NOTIFICATION_SHADE,该特殊类型允许它在其他系统窗口之上接收输入事件。// frameworks/base/packages/SystemUI/src/com/android/systemui/shade/ // NotificationShadeWindowControllerImpl.java @SysUISingleton public class NotificationShadeWindowControllerImpl implements NotificationShadeWindowController, Dumpable { // Manages the notification shade window parameters // Adjusts focus, touchability, and dimensions based on state }窗口控制器根据当前状态动态修改窗口参数:状态窗口行为面板收起不可获取焦点,高度最小面板展开中高度变化,接收触摸事件面板完全展开全屏,支持远程输入,可获得焦点锁屏全屏,密码输入界面可获取焦点息屏 AOD最小尺寸,低功耗48.3.2 NotificationPanelViewControllerNotificationPanelViewController代码约 4300 行,是 Scene 框架之前传统面板的主控制器。负责:触摸跟踪与基于滑动速度的展开 / 收起面板内部快捷设置展开锁屏专属行为(时钟、锁屏通知)大屏分栏模式(通知居左,快捷设置居右)展开过程的模糊效果// frameworks/base/packages/SystemUI/src/com/android/systemui/shade/ // NotificationPanelViewController.java public class NotificationPanelViewController implements Dumpable, ShadeSurface { // Handles all shade panel touch events and state transitions }该控制器属于遗留大组件,正是 Scene 框架要替换的对象。当SceneContainerFlag开启,本类中的下拉展开、快捷设置展开逻辑全部替换为SceneTransitionLayout,NotificationPanelViewController不再执行。主要触摸处理流程:48.3.3 ShadeControllerShadeController是抽象面板操作接口,继承CoreStartable:// frameworks/base/packages/SystemUI/src/com/android/systemui/shade/ // ShadeController.java public interface ShadeController extends CoreStartable { boolean isShadeEnabled(); void instantExpandShade(); void instantCollapseShade(); void animateCollapseShade(int flags, boolean force, boolean delayed, float speedUpFactor); void animateExpandShade(); void animateExpandQs(); void cancelExpansionAndCollapseShade(); boolean isShadeFullyOpen(); boolean isExpandingOrCollapsing(); void collapseShade(); void collapseShadeForActivityStart(); // ... }默认实现为ShadeControllerImpl(约 410 行);ShadeControllerSceneImpl是 Scene 容器架构下下一代实现。QuickSettingsController同样两套实现:传统路径QuickSettingsControllerImpl.java,Scene 路径QuickSettingsControllerSceneImpl.kt。Dagger 根据SceneContainerFlag绑定其中一个实现。48.3.4 NotificationStackScrollLayout通知列表渲染由NotificationStackScrollLayout这个自定义 ViewGroup 完成,能力包含:子 View 高度可变(通知条目)越界滚动物理效果侧滑清除手势通知分组与分组头部弹窗通知插入溢出图标收纳 Shelf每一条通知行是ExpandableNotificationRow,内部包含收缩、展开、弹窗模式的通知布局。48.3.5 遮罩层管理面板背后的遮罩层(Scrim)由ScrimController管理,维护多层遮罩:每个 ScrimState 定义各层透明度与着色,状态切换带动属性平滑动画。48.3.6 锁屏到通知面板转场LockscreenShadeTransitionController处理从锁屏界面向下拖拽打开通知面板手势。协调:快捷设置展开系数遮罩透明度动画锁屏可见性通知位置插值48.4 快捷设置 (QS)快捷设置是下拉通知面板访问到的磁贴网格。第一次下拉展示精简快捷设置条,再次下拉展开完整快捷设置面板。48.4.1 架构总览48.4.2 QSHost —— 磁贴管理QSHost接口管理全部激活的快捷磁贴集合:// frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSHost.java public interface QSHost { String TILES_SETTING = Settings.Secure.QS_TILES; int POSITION_AT_END = -1; static ListString getDefaultSpecs(Resources res) { final ArrayListString tiles = new ArrayList(); int resource = QsSplitInternetTile.isEnabled() ? R.string.quick_settings_tiles_default_split : R.string.quick_settings_tiles_default; final String defaultTileList = res.getString(resource); tiles.addAll(Arrays.asList(defaultTileList.split(","))); return tiles; } CollectionQSTile getTiles(); void removeTile(String tileSpec); void removeTiles(CollectionString specs); QSTile createTile(String tileSpec); void addCallback(Callback callback); ListString getSpecs(); }磁贴配置保存在Settings.Secure.QS_TILES,逗号分隔磁贴标识,例如"wifi,bt,flashlight,rotation"。默认磁贴集合定义在字符串资源,OEM 经常通过资源 Overlay 修改。48.4.3 QSTile 接口每一块快捷磁贴都实现QSTile插件接口: