当前位置: 首页 > news >正文

Android14的QS面板的加载解析

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java

QS 面板的创建

  1. getNotificationShadeWindowView():整个systemui的最顶级的视图容器(super_notification_shade.xml)
  2. R.id.qs_frame : 是整个QS 面板的容器视图
  3. mQSPanelController:获取其内部的 QSPanelController(QS 面板的控制器,负责管理快捷开关的显示、点击事件等)
// Set up the quick settings tile paneprotected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {......final View container = getNotificationShadeWindowView().findViewById(R.id.qs_frame);if (container != null) {//FragmentHostManager:是 SystemUI 中用于管理 Fragment 与宿主视图(这里即 container)关联的工具类,负责 Fragment 的添加、移除、生命周期绑定等。FragmentHostManager fragmentHostManager =mFragmentService.getFragmentHostManager(container);ExtensionFragmentListener.attachExtensonToFragment(mFragmentService,container,QS.TAG,R.id.qs_frame,mExtensionController.newExtension(QS.class).withPlugin(QS.class).withDefault(this::createDefaultQSFragment).build());mBrightnessMirrorController = new BrightnessMirrorController(getNotificationShadeWindowView(),mShadeSurface,mNotificationShadeDepthControllerLazy.get(),mBrightnessSliderFactory,(visible) -> {mBrightnessMirrorVisible = visible;updateScrimController();});//给 fragmentHostManager 添加一个标签监听器,监听 QS.TAG 对应的 Fragment(即 QS 面板的 Fragment)的生命周期变化(如 Fragment 被创建或绑定到容器时)fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {QS qs = (QS) f;if (qs instanceof QSFragment) {mQSPanelController = ((QSFragment) qs).getQSPanelController();((QSFragment) qs).setBrightnessMirrorController(mBrightnessMirrorController);}});}
}

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java

这里开始看创建面板QSFragment

    protected QS createDefaultQSFragment() {return mFragmentService.getFragmentHostManager(getNotificationShadeWindowView()).create(QSFragment.class);}

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java

QSFragment 初始化

!!!这里的 qsFragmentComponent.getQSPanelController是重点,返回QSPanelController对象

    @Overridepublic void onViewCreated(View view, @Nullable Bundle savedInstanceState) {QSFragmentComponent qsFragmentComponent = mQsComponentFactory.create(this);mQSPanelController = qsFragmentComponent.getQSPanelController();mQuickQSPanelController = qsFragmentComponent.getQuickQSPanelController();mQSPanelController.init();mQuickQSPanelController.init();

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java

QSPanelController初始化

!!!这里开始QSHost开始被注入创建,QSHost主要是数据源!!!

 @InjectQSPanelController(QSPanel view, TunerService tunerService,QSHost qsHost, QSCustomizerController qsCustomizerController,@Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,@Named(QS_PANEL) MediaHost mediaHost,QSTileRevealController.Factory qsTileRevealControllerFactory,DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,BrightnessSliderController.Factory brightnessSliderFactory,FalsingManager falsingManager,StatusBarKeyguardViewManager statusBarKeyguardViewManager) {super(view, qsHost, qsCustomizerController, usingMediaPlayer, mediaHost,metricsLogger, uiEventLogger, qsLogger, dumpManager);

QSHost提供实现类是QSHostAdapter

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/dagger/QSHostModule.kt

@Module
interface QSHostModule {//@Binds: 表明QSHostAdapter是QSHost的具体实现类,当其他类通过 Dagger 注入 QSHost 时(比如在构造函数中声明 @Inject constructor(private val qsHost: QSHost)),Dagger 会自动创建 QSHostAdapter 的实例@Binds fun provideQsHost(controllerImpl: QSHostAdapter): QSHost
}

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt

QSHostAdapter其实只是一个包装类,具体实现是QSTileHost,记住这个地方

QSTileHost从此刻开始被注入创建

constructor(private val qsTileHost: QSTileHost,private val interactor: CurrentTilesInteractor,private val context: Context,private val tileServiceRequestControllerBuilder: TileServiceRequestController.Builder,@Application private val scope: CoroutineScope,private val featureFlags: FeatureFlags,dumpManager: DumpManager,
) : QSHost {

QSTileHost开始初始化

主要看这个tunerService.addTunable(this, TILES_SETTING);

    @Injectpublic QSTileHost(Context context,QSFactory defaultFactory,@Main Executor mainExecutor,PluginManager pluginManager,TunerService tunerService,Provider<AutoTileManager> autoTiles,ShadeController shadeController,QSLogger qsLogger,UserTracker userTracker,SecureSettings secureSettings,CustomTileStatePersister customTileStatePersister,TileLifecycleManager.Factory tileLifecycleManagerFactory,UserFileManager userFileManager,FeatureFlags featureFlags) {mainExecutor.execute(() -> {// This is technically a hack to avoid circular dependency of// QSTileHost -> XXXTile -> QSTileHost. Posting ensures creation// finishes before creating any tiles.//这个在	QSHost 中定义的String TILES_SETTING = Settings.Secure.QS_TILES;tunerService.addTunable(this, TILES_SETTING);// AutoTileManager can modify mTiles so make sure mTiles has already been initialized.if (!mFeatureFlags.isEnabled(Flags.QS_PIPELINE_AUTO_ADD)) {mAutoTiles = autoTiles.get();}});}

其实最后调用了QSTileHost的onTuningChanged方法

这里进行数据获取!!!

private final LinkedHashMap<String, QSTile> mTiles = new LinkedHashMap<>();@MainThread@Overridepublic void onTuningChanged(String key, String newValue) {if (!TILES_SETTING.equals(key)) {return;}int currentUser = mUserTracker.getUserId();if (currentUser != mCurrentUser) {mUserContext = mUserTracker.getUserContext();if (mAutoTiles != null) {mAutoTiles.changeUser(UserHandle.of(currentUser));}}// Do not process tiles if the flag is enabled.if (mFeatureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) {return;}if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) {newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode);}final List<String> tileSpecs = loadTileSpecs(mContext, newValue);if (tileSpecs.equals(mTileSpecs) && currentUser == mCurrentUser) return;Log.d(TAG, "Recreating tiles: " + tileSpecs);mTiles.entrySet().stream().filter(tile -> !tileSpecs.contains(tile.getKey())).forEach(tile -> {Log.d(TAG, "Destroying tile: " + tile.getKey());mQSLogger.logTileDestroyed(tile.getKey(), "Tile removed");tile.getValue().destroy();});final LinkedHashMap<String, QSTile> newTiles = new LinkedHashMap<>();for (String tileSpec : tileSpecs) {QSTile tile = mTiles.get(tileSpec);if (tile != null && (!(tile instanceof CustomTile)|| ((CustomTile) tile).getUser() == currentUser)) {if (tile.isAvailable()) {Log.d(TAG, "Adding " + tile);tile.removeCallbacks();if (!(tile instanceof CustomTile) && mCurrentUser != currentUser) {tile.userSwitch(currentUser);}newTiles.put(tileSpec, tile);mQSLogger.logTileAdded(tileSpec);} else {tile.destroy();Log.d(TAG, "Destroying not available tile: " + tileSpec);mQSLogger.logTileDestroyed(tileSpec, "Tile not available");}} else {// This means that the tile is a CustomTile AND the user is different, so let's// destroy itif (tile != null) {tile.destroy();Log.d(TAG, "Destroying tile for wrong user: " + tileSpec);mQSLogger.logTileDestroyed(tileSpec, "Tile for wrong user");}Log.d(TAG, "Creating tile: " + tileSpec);try {tile = createTile(tileSpec);if (tile != null) {tile.setTileSpec(tileSpec);if (tile.isAvailable()) {newTiles.put(tileSpec, tile);mQSLogger.logTileAdded(tileSpec);} else {tile.destroy();Log.d(TAG, "Destroying not available tile: " + tileSpec);mQSLogger.logTileDestroyed(tileSpec, "Tile not available");}} else {Log.d(TAG, "No factory for a spec: " + tileSpec);}} catch (Throwable t) {Log.w(TAG, "Error creating tile for spec: " + tileSpec, t);}}}........}

看这个loadTileSpecs

quick_settings_tiles:config.xml中的值是default

 protected static List<String> loadTileSpecs(Context context, String tileList) {final Resources res = context.getResources();if (TextUtils.isEmpty(tileList)) {tileList = res.getString(R.string.quick_settings_tiles);Log.d(TAG, "Loaded tile specs from default config: " + tileList);} else {Log.d(TAG, "Loaded tile specs from setting: " + tileList);}final ArrayList<String> tiles = new ArrayList<String>();boolean addedDefault = false;Set<String> addedSpecs = new ArraySet<>();for (String tile : tileList.split(",")) {tile = tile.trim();if (tile.isEmpty()) continue;if (tile.equals("default")) {if (!addedDefault) {List<String> defaultSpecs = QSHost.getDefaultSpecs(context.getResources());for (String spec : defaultSpecs) {if (!addedSpecs.contains(spec)) {tiles.add(spec);addedSpecs.add(spec);}}addedDefault = true;}} else {if (!addedSpecs.contains(tile)) {tiles.add(tile);addedSpecs.add(tile);}}}if (!tiles.contains("internet")) {if (tiles.contains("wifi")) {// Replace the WiFi with Internet, and remove the Celltiles.set(tiles.indexOf("wifi"), "internet");tiles.remove("cell");} else if (tiles.contains("cell")) {// Replace the Cell with Internettiles.set(tiles.indexOf("cell"), "internet");}} else {tiles.remove("wifi");tiles.remove("cell");}return tiles;}

QSHost

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSHost.java

加载quick_settings_tiles_default是config下的配置文件,默认显示下拉状态栏的tiles

    /*** Returns the default QS tiles for the context.* @param res the resources to use to determine the default tiles* @return a list of specs of the default tiles*/static List<String> getDefaultSpecs(Resources res) {final ArrayList<String> tiles = new ArrayList();final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);tiles.addAll(Arrays.asList(defaultTileList.split(",")));if (Build.IS_DEBUGGABLE&& GarbageMonitor.ADD_MEMORY_TILE_TO_DEFAULT_ON_DEBUGGABLE_BUILDS) {tiles.add(GarbageMonitor.MemoryTile.TILE_SPEC);}return tiles;}

这时候的数据已经加载完,接下来看创建Tile实例

    private final ArrayList<QSFactory> mQsFactories = new ArrayList<>();public QSTile createTile(String tileSpec) {for (int i = 0; i < mQsFactories.size(); i++) {QSTile t = mQsFactories.get(i).createTile(tileSpec);if (t != null) {return t;}}return null;}

!!!其实是QSFactoryImpl 去createTile!!!

经过bind自动注入到mTileMap中了,
这时候用quick_settings_tiles_default去跟mTileMap比较是否存在,存在就返回对应注入好的Tile实例对象

/** Inject FontScalingTile into tileMap in QSModule */
@Binds
@IntoMap
@StringKey(FontScalingTile.TILE_SPEC)
fun bindFontScalingTile(fontScalingTile: FontScalingTile): QSTileImpl<*>

@SysUISingleton
public class QSFactoryImpl implements QSFactory {private static final String TAG = "QSFactory";protected final Map<String, Provider<QSTileImpl<?>>> mTileMap;private final Lazy<QSHost> mQsHostLazy;private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;@Injectpublic QSFactoryImpl(Lazy<QSHost> qsHostLazy,Provider<CustomTile.Builder> customTileBuilderProvider,Map<String, Provider<QSTileImpl<?>>> tileMap) {mQsHostLazy = qsHostLazy;mCustomTileBuilderProvider = customTileBuilderProvider;mTileMap = tileMap;}/** Creates a tile with a type based on {@code tileSpec} */@Nullablepublic final QSTile createTile(String tileSpec) {QSTileImpl tile = createTileInternal(tileSpec);if (tile != null) {tile.initialize();tile.postStale(); // Tile was just created, must be stale.}return tile;}@Nullableprotected QSTileImpl createTileInternal(String tileSpec) {// Stock tiles.if (mTileMap.containsKey(tileSpec)// We should not return a Garbage Monitory Tile if the build is not Debuggable&& (!tileSpec.equals(GarbageMonitor.MemoryTile.TILE_SPEC) || Build.IS_DEBUGGABLE)) {return mTileMap.get(tileSpec).get();}// Custom tilesif (tileSpec.startsWith(CustomTile.PREFIX)) {return CustomTile.create(mCustomTileBuilderProvider.get(), tileSpec, mQsHostLazy.get().getUserContext());}// Broken tiles.Log.w(TAG, "No stock tile spec: " + tileSpec);return null;}@Overridepublic QSTileView createTileView(Context context, QSTile tile, boolean collapsedView) {QSIconView icon = tile.createTileView(context);return new QSTileViewImpl(context, icon, collapsedView);}

最重要的这一步,获取到全部的数据缓存在mTiles中保存!!!

用户视图加载数据用!!!
public Collection getTiles() {return mTiles.values();}

  @MainThread@Overridepublic void onTuningChanged(String key, String newValue) {......mCurrentUser = currentUser;List<String> currentSpecs = new ArrayList<>(mTileSpecs);mTileSpecs.clear();mTileSpecs.addAll(newTiles.keySet()); // Only add the valid (available) tiles.mTiles.clear();mTiles.putAll(newTiles);if (newTiles.isEmpty() && !tileSpecs.isEmpty()) {// If we didn't manage to create any tiles, set it to empty (default)Log.d(TAG, "No valid tiles on tuning changed. Setting to default.");changeTilesByUser(currentSpecs, loadTileSpecs(mContext, ""));} else {String resolvedTiles = TextUtils.join(",", mTileSpecs);if (!resolvedTiles.equals(newValue)) {// If the resolved tiles (those we actually ended up with) are different than// the ones that are in the setting, update the Setting.// 用TILES_SETTING进行缓存下拉状态栏的数据saveTilesToSettings(mTileSpecs);}mTilesListDirty = false;for (int i = 0; i < mCallbacks.size(); i++) {mCallbacks.get(i).onTilesChanged();}}
}

接下来再看QSFragment 初始化,这时候数据类都已经加载好了,开始把数据加载进视图里面去了

mQSPanelController.init开始初始化,
/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {QSFragmentComponent qsFragmentComponent = mQsComponentFactory.create(this);//start 这里调用完后数据已经加载完毕mQSPanelController = qsFragmentComponent.getQSPanelController();//endmQuickQSPanelController = qsFragmentComponent.getQuickQSPanelController();//数据加载进视图mQSPanelController.init();mQuickQSPanelController.init();

这个init()这里调用的其实是他的基类的init

/frameworks/base/packages/SystemUI/src/com/android/systemui/util/ViewController.java
这里其实是调用子类onViewAttached

 */
public abstract class ViewController<T extends View> {protected final T mView;private boolean mInited;private OnAttachStateChangeListener mOnAttachStateListener = new OnAttachStateChangeListener() {@Overridepublic void onViewAttachedToWindow(View v) {ViewController.this.onViewAttached();}@Overridepublic void onViewDetachedFromWindow(View v) {ViewController.this.onViewDetached();}};protected ViewController(T view) {mView = view;}/*** Call immediately after constructing Controller in order to handle view lifecycle events.** Generally speaking, you don't want to override this method. Instead, override* {@link #onInit()} as a way to have an run-once idempotent method that you can use for* setup of your ViewController.*/public void init() {if (mInited) {return;}onInit();mInited = true;if (isAttachedToWindow()) {mOnAttachStateListener.onViewAttachedToWindow(mView);}addOnAttachStateChangeListener(mOnAttachStateListener);}

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java

这里是最重要的

这里获取QSTileHost.getTiles()的数据进行数据与视图绑定了
mView这个View是QSPanel,是QSPanelController这个类通过super传递给QSPanelControllerBase的
QSPanelController(QSPanel view, TunerService tunerService,....)
super(view,......)

    @Overrideprotected void onViewAttached() {mQsTileRevealController = createTileRevealController();if (mQsTileRevealController != null) {mQsTileRevealController.setExpansion(mRevealExpansion);}mMediaHost.addVisibilityChangeListener(mMediaHostVisibilityListener);mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);mHost.addCallback(mQSHostCallback);setTiles();mLastOrientation = getResources().getConfiguration().orientation;mQSLogger.logOnViewAttached(mLastOrientation, mView.getDumpableTag());switchTileLayout(true);mDumpManager.registerDumpable(mView.getDumpableTag(), this);}/** */public void setTiles() {setTiles(mHost.getTiles(), false);}/** */public void setTiles(Collection<QSTile> tiles, boolean collapsedView) {// TODO(b/168904199): move this logic into QSPanelController.if (!collapsedView && mQsTileRevealController != null) {mQsTileRevealController.updateRevealedTiles(tiles);}for (QSPanelControllerBase.TileRecord record : mRecords) {mView.removeTile(record);record.tile.removeCallback(record.callback);}mRecords.clear();mCachedSpecs = "";for (QSTile tile : tiles) {addTile(tile, collapsedView);}}private void addTile(final QSTile tile, boolean collapsedView) {final TileRecord r =new TileRecord(tile, mHost.createTileView(getContext(), tile, collapsedView));// TODO(b/250618218): Remove the QSLogger in QSTileViewImpl once we know the root cause of// b/250618218.try {QSTileViewImpl qsTileView = (QSTileViewImpl) (r.tileView);if (qsTileView != null) {qsTileView.setQsLogger(mQSLogger);}} catch (ClassCastException e) {Log.e(TAG, "Failed to cast QSTileView to QSTileViewImpl", e);}mView.addTile(r);mRecords.add(r);mCachedSpecs = getTilesSpecs();}

QSPanel

mTileLayout 中添加addTile

final void addTile(QSPanelControllerBase.TileRecord tileRecord) {final QSTile.Callback callback = new QSTile.Callback() {@Overridepublic void onStateChanged(QSTile.State state) {drawTile(tileRecord, state);}};tileRecord.tile.addCallback(callback);tileRecord.callback = callback;tileRecord.tileView.init(tileRecord.tile);tileRecord.tile.refreshState();if (mTileLayout != null) {mTileLayout.addTile(tileRecord);}}

TileLayout

    public void addTile(TileRecord tile) {mRecords.add(tile);tile.tile.setListening(this, mListening);addTileView(tile);}protected void addTileView(TileRecord tile) {addView(tile.tileView); 添加子view并刷新}
http://www.lryc.cn/news/612370.html

相关文章:

  • 【android bluetooth 协议分析 03】【蓝牙扫描详解 4】【BR/EDR扫描到设备后如何上报给app侧】
  • 力扣137:只出现一次的数字Ⅱ
  • 【计算机网络 | 第4篇】分组交换
  • Javascript/ES6+/Typescript重点内容篇——手撕(待总结)
  • Spring之【初识AOP】
  • hf的国内平替hf-mirror
  • IAR软件中测量函数执行时间
  • 开发笔记 | 接口与抽象基类说明以及对象池的实现
  • 机器学习 朴素贝叶斯
  • 【普通地质学】地球的物质组成
  • iOS混淆工具有哪些?在集成第三方 SDK 时的混淆策略与工具建议
  • MEMS陀螺仪如何在复杂井下环境中保持精准测量?
  • 以此芯p1芯片为例研究OpenHarmony上GPU (Vulkan) 加速在深度学习推理中的价值
  • n8n Slack credentials(n8n slack凭证配置步骤)(API access token)
  • Datawhale AI 夏令营:RAG多模态检索(Baseline解读)
  • 解决启动docker报错Cannot connect to the Docker daemon问题
  • Windows 如何上架 iOS 应用?签名上传全流程 + 工具推荐
  • 使用CRC32爆破ZIP压缩包内小文件内容的技术解析
  • app-3
  • Python面试题及详细答案150道(01-15) -- 基础语法篇
  • 译 | 在 Python 中从头开始构建 Qwen-3 MoE
  • 三轴云台之机械结构篇
  • ubuntu server 工业环境部署手册[2025-08-06]
  • 查看ubuntu server 的基本信息
  • Node.js从入门到精通完整指南
  • 服务器重启后mysql5.7启动失败问题
  • [激光原理与应用-163]:光机械件 - 光机械件的工程技术难点
  • .Net下载共享文件夹中的文件
  • NCD57080CDR2G 安森美onsemi 通用驱动器, SOIC, 8针, 20V电源, 8 A输出NCD57080CDR2电流隔离式栅极驱动器
  • C++11之智能指针