欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > Android SystemUI——快捷面板的创建(十四)

Android SystemUI——快捷面板的创建(十四)

2025/1/22 8:08:59 来源:https://blog.csdn.net/c19344881x/article/details/145037313  浏览:    关键词:Android SystemUI——快捷面板的创建(十四)

        上一篇文章介绍了快捷面板界面 QSFragment 的创建流程,这里我们继续介绍快捷按键 QSTile 和管理 QSTile 生命周期和服务注册的 QSTileHost。

一、QSTileHost初始化

        Android 9.0 以及之前的版本,实例化 QSTileHost 类是在 StatusBar 的 makeStatusBarView() 方法中。

1、StatusBar

源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {……// 设置快速设置面板final View container = mNotificationShadeWindowView.findViewById(R.id.qs_frame);if (container != null) {……fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {QS qs = (QS) f;if (qs instanceof QSFragment) {((QSFragment) qs).setHost(qsh);mQSPanel = ((QSFragment) qs).getQsPanel();mQSPanel.setBrightnessMirror(mBrightnessMirrorController);mKeyguardStatusBar.setQSPanel(mQSPanel);}});}……
}

        这里调用 setHost() 方法对 QSTileHost 进行初始化,而对于 Android 9.0 以上的版本,则是在 QSFragment 的构造函数中通过 Dagger2 注解的方式进行初始化。

2、QSFragment

源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java

@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,InjectionInflationController injectionInflater, QSTileHost qsTileHost,StatusBarStateController statusBarStateController, CommandQueue commandQueue,QSDetailDisplayer qsDetailDisplayer, @Named(QS_PANEL) MediaHost qsMediaHost,@Named(QUICK_QS_PANEL) MediaHost qqsMediaHost,KeyguardBypassController keyguardBypassController,QSFragmentComponent.Factory qsComponentFactory, FeatureFlags featureFlags,FalsingManager falsingManager, DumpManager dumpManager) {……mHost = qsTileHost;……
}

二、QS创建

1、QSTileHost

源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java

@Inject
public QSTileHost(Context context,StatusBarIconController iconController,QSFactory defaultFactory,@Main Handler mainHandler,@Background Looper bgLooper,PluginManager pluginManager,TunerService tunerService,Provider<AutoTileManager> autoTiles,DumpManager dumpManager,BroadcastDispatcher broadcastDispatcher,Optional<StatusBar> statusBarOptional,QSLogger qsLogger,UiEventLogger uiEventLogger,UserTracker userTracker,SecureSettings secureSettings,CustomTileStatePersister customTileStatePersister
) {……mainHandler.post(() -> {// 在创建任何图块之前完成。tunerService.addTunable(this, TILES_SETTING);// AutoTileManager 可以修改 mTiles,因此请确保 mTiles 已经初始化。mAutoTiles = autoTiles.get();});
}

        在 QSTileHost 的构造函数里,调用 TunerService 里的 addTunabe() 方法,最该方法最终实现是在 TunerServiceImpl 中完成。

2、TunerServiceImpl

源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java

addTunable

@Override
public void addTunable(Tunable tunable, String... keys) {for (String key : keys) {addTunable(tunable, key);}
}private void addTunable(Tunable tunable, String key) {……// 从数据库读取数据,刷机第一次数据库为空,这里也会空,后面程序会从配置文件读取String value = DejankUtils.whitelistIpcs(() -> Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser));tunable.onTuningChanged(key, value);
} 

        这里最终调用 QSTileHost 的 onTuningChanged() 回调。

3、QSTileHost

onTuningChanged

@Override
public void onTuningChanged(String key, String newValue) {……// 获得 config 里字符串信息final List<String> tileSpecs = loadTileSpecs(mContext, newValue);int currentUser = mUserTracker.getUserId();……// 检查是否需要更新if (tileSpecs.equals(mTileSpecs) && currentUser == mCurrentUser) return;// 移除不再需要的图块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)) { // 更新图块……} else { // 创建图块// 图块不可用或创建失败,则销毁if (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 {// 通过字符串实例化Tiletile = 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");}}} catch (Throwable t) {Log.w(TAG, "Error creating tile for spec: " + tileSpec, t);}}}// 更新状态和通知回调mCurrentUser = currentUser;List<String> currentSpecs = new ArrayList<>(mTileSpecs);mTileSpecs.clear();mTileSpecs.addAll(tileSpecs);mTiles.clear();mTiles.putAll(newTiles);if (newTiles.isEmpty() && !tileSpecs.isEmpty()) {// 如果没有任何有效的图块被创建,则恢复默认配置changeTiles(currentSpecs, loadTileSpecs(mContext, ""));} else {for (int i = 0; i < mCallbacks.size(); i++) {// 通知所有监听者图块已更改mCallbacks.get(i).onTilesChanged();}}
}

        这里主要调用 loadTileSpecs() 方法获取 config 里字符串信息,然后调用 createTile() 方法实例化 Tile。 

loadTileSpecs

protected static List<String> loadTileSpecs(Context context, String tileList) {// 初始化资源对象final Resources res = context.getResources();// 如果传入的tileList为空,则从资源文件中加载默认的图块列表if (TextUtils.isEmpty(tileList)) {tileList = res.getString(R.string.quick_settings_tiles);}……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 = getDefaultSpecs(context);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);}}}return tiles;
}

        该方法主要负责从配置或设置中加载快捷设置图块(tiles)的规格,并确保这些规格被正确解析和去重。

createTile

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;
}

        这里调用 QSFactory 的 createTile() 方法,而 QSFactory 接口又由 QSFactoryImpl 实现。

4、QSFactoryImpl

源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java

createTile

public QSTile createTile(String tileSpec) {QSTileImpl tile = createTileInternal(tileSpec);if (tile != null) {tile.initialize();tile.postStale(); // Tile was just created, must be stale.}return tile;
}

        这里又调用了 createTileInternal() 方法。 

createTileInternal

private QSTileImpl createTileInternal(String tileSpec) {// Stock tiles.switch (tileSpec) {case "wifi":return mWifiTileProvider.get();case "internet":return mInternetTileProvider.get();case "bt":return mBluetoothTileProvider.get();case "cell":return mCellularTileProvider.get();case "dnd":return mDndTileProvider.get();case "inversion":return mColorInversionTileProvider.get();case "airplane":return mAirplaneModeTileProvider.get();case "work":return mWorkModeTileProvider.get();case "rotation":return mRotationLockTileProvider.get();case "flashlight":return mFlashlightTileProvider.get();case "location":return mLocationTileProvider.get();case "cast":return mCastTileProvider.get();case "hotspot":return mHotspotTileProvider.get();case "user":return mUserTileProvider.get();case "battery":return mBatterySaverTileProvider.get();case "saver":return mDataSaverTileProvider.get();case "night":return mNightDisplayTileProvider.get();case "nfc":return mNfcTileProvider.get();case "dark":return mUiModeNightTileProvider.get();case "screenrecord":return mScreenRecordTileProvider.get();case "reduce_brightness":return mReduceBrightColorsTileProvider.get();case "cameratoggle":return mCameraToggleTileProvider.get();case "mictoggle":return mMicrophoneToggleTileProvider.get();case "controls":return mDeviceControlsTileProvider.get();case "alarm":return mAlarmTileProvider.get();case "wallet":return mQuickAccessWalletTileProvider.get();}……return null;
}

        可以看到这里通过对应的字符串分别实例化了对应的 Tile。 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com