quick settings是statusbar的一部分,随着statusbarview的创建而加载,上一篇SystemUI源码分析三中已经分析了statusbar的加载流程,那么这里将继续对其中的quick settings部分进行简单的分析,弄清楚它的加载显示流程。首先从PhoneStausBar.java中开始分析。
protected PhoneStatusBarView makeStatusBarView() {
final Context context = mContext;
// Set up the quick settings tile panel
mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
if (mQSPanel != null) {
final QSTileHost qsh = new QSTileHost(mContext, this,
mBluetoothController, mLocationController, mRotationLockController,
mNetworkController, mZenModeController, mHotspotController,
mCastController, mFlashlightController,
mUserSwitcherController, mKeyguardMonitor,
mSecurityController);
mQSPanel.setHost(qsh);
mQSPanel.setTiles(qsh.getTiles());
mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
mHeader.setQSPanel(mQSPanel);
qsh.setCallback(new QSTileHost.Callback() {
@Override
public void onTilesChanged() {
mQSPanel.setTiles(qsh.getTiles());
}
});
}
}
1、获得QSPanel这个viewgroup,然后创建QSTileHost对象,通过调用QSPanel的setHost()函数将QSTileHost对象传递给QSPanel.java.
QSTileHost的构造方法分析
protected static final String TILES_SETTING = "sysui_qs_tiles";
public QSTileHost(Context context, PhoneStatusBar statusBar,
BluetoothController bluetooth, LocationController location,
RotationLockController rotation, NetworkController network,
ZenModeController zen, HotspotController hotspot,
CastController cast, FlashlightController flashlight,
UserSwitcherController userSwitcher, KeyguardMonitor keyguard,
SecurityController security) {
mContext = context;
mStatusBar = statusBar;
mBluetooth = bluetooth;
mLocation = location;
mRotation = rotation;
mNetwork = network;
mZen = zen;
mHotspot = hotspot;
mCast = cast;
mFlashlight = flashlight;
mUserSwitcherController = userSwitcher;
mKeyguard = keyguard;
mSecurity = security;
final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
Process.THREAD_PRIORITY_BACKGROUND);
ht.start();
mLooper = ht.getLooper();
TunerService.get(mContext).addTunable(this, TILES_SETTING);
}
调用TunerService.get(mContext).addTunable()函数查询TILES_SETTING
TunerService.java
private void addTunable(Tunable tunable, String key) {
if (!mTunableLookup.containsKey(key)) {
mTunableLookup.put(key, new ArrayList());
}
mTunableLookup.get(key).add(tunable);
Uri uri = Settings.Secure.getUriFor(key);
if (!mListeningUris.containsKey(uri)) {
mListeningUris.put(uri, key);
mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
}
// Send the first state.
String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
tunable.onTuningChanged(key, value);
}
tunable.onTuningChanged(key, value);查询到的结果通过这个回调方法返回
QSTileHost.java
@Override
public void onTuningChanged(String key, String newValue) {
if (!TILES_SETTING.equals(key)) {
return;
}
if (DEBUG) Log.d(TAG, "Recreating tiles");
final List<String> tileSpecs = loadTileSpecs(newValue);
if (tileSpecs.equals(mTileSpecs)) return;
for (Map.Entry<String, QSTile>> tile : mTiles.entrySet()) {
if (!tileSpecs.contains(tile.getKey())) {
if (DEBUG) Log.d(TAG, "Destroying tile: " + tile.getKey());
tile.getValue().destroy();
}
}
final LinkedHashMap<String, QSTile>> newTiles = new LinkedHashMap<>();
for (String tileSpec : tileSpecs) {
if (mTiles.containsKey(tileSpec)) {
newTiles.put(tileSpec, mTiles.get(tileSpec));
} else {
if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec);
try {
newTiles.put(tileSpec, createTile(tileSpec));
} catch (Throwable t) {
Log.w(TAG, "Error creating tile for spec: " + tileSpec, t);
}
}
}
mTileSpecs.clear();
mTileSpecs.addAll(tileSpecs);
mTiles.clear();
mTiles.putAll(newTiles);
if (mCallback != null) {
mCallback.onTilesChanged();
}
}
这个函数主要做的是:
1.1、loadTileSpecs(newValue);//加载默认的tileSpecs。
protected List<String> loadTileSpecs(String tileList) {
final Resources res = mContext.getResources();
String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
if (!TelephonyManager.isDeviceSupportLte()) {
defaultTileList = defaultTileList.replace(",lte", "");
}
if (tileList == null) {
tileList = res.getString(R.string.quick_settings_tiles);
if (DEBUG) Log.d(TAG, "Loaded tile specs from config: " + tileList);
} else {
if (DEBUG) Log.d(TAG, "Loaded tile specs from setting: " + tileList);
}
final ArrayList<String> tiles = new ArrayList<String>();
boolean addedDefault = false;
for (String tile : tileList.split(",")) {
tile = tile.trim();
if (tile.isEmpty()) continue;
if (tile.equals("default")) {
if (!addedDefault) {
tiles.addAll(Arrays.asList(defaultTileList.split(",")));
addedDefault = true;
}
} else {
tiles.add(tile);
}
}
return tiles;
}
1.2、for循坏遍历tileSpecs集合,把信息保存在newTiles这个map集合中,最后全部保存在mTiles集合。
1.3、newTiles.put(tileSpec, createTile(tileSpec));创建快捷设置tile的对象。
protected QSTile> createTile(String tileSpec) {
if (tileSpec.equals("wifi") && !WCN_DISABLED) return new WifiTile(this);
else if (tileSpec.equals("bt") && !WCN_DISABLED) return new BluetoothTile(this);
else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
else if (tileSpec.equals("cell")) return new CellularTile(this);
else if (tileSpec.equals("data")) return new DataConnectionTile(this);
else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this);
else if (tileSpec.equals("lte") && TelephonyManager.isDeviceSupportLte()
&& SystemUIPluginsHelper.getInstance().show4GInQS())
return new LteServiceTile(this);
else if (tileSpec.equals("dnd")) return new DndTile(this);
else if (tileSpec.equals("rotation")) return new RotationLockTile(this);
else if (tileSpec.equals("flashlight")) return new FlashlightTile(this);
else if (tileSpec.equals("location") && !WCN_DISABLED) return new LocationTile(this);
else if (tileSpec.equals("cast") && !WCN_DISABLED && mContext.getResources().getBoolean(
com.android.internal.R.bool.config_enableWifiDisplay)) return new CastTile(this);
else if (tileSpec.equals("audioprofile")) return new AudioProfileTile(this);
else if (tileSpec.equals("hotspot") && !WCN_DISABLED) return new HotspotTile(this);
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
}
1.4、mCallback.onTilesChanged();//回调onTilesChanged()函数,通知PhoneStatus.java对快捷设置项显示更新。
那在回到PhoneStatusBar.java中的makeStatusBarView()函数中分析。
2、mQSPanel.setTiles(qsh.getTiles());在上面我们提到加载的快捷设置tiles都保存在了mTiles集合中。QSTileHost.java中提供了getTiles()方法取得mTiles集合。
QSPanel.java
public void setTiles(Collection> tiles) {
for (TileRecord record : mRecords) {
removeView(record.tileView);
}
mRecords.clear();
for (QSTile> tile : tiles) {
addTile(tile);
}
if (isShowingDetail()) {
mDetail.bringToFront();
}
}
private void addTile(final QSTile> tile) {
final TileRecord r = new TileRecord();
r.tile = tile;
r.tileView = tile.createTileView(mContext);
r.tileView.setVisibility(View.GONE);
final QSTile.Callback callback = new QSTile.Callback() {
@Override
public void onStateChanged(QSTile.State state) {
if (!r.openingDetail) {
drawTile(r, state);
}
}
@Override
public void onShowDetail(boolean show) {
QSPanel.this.showDetail(show, r);
}
@Override
public void onToggleStateChanged(boolean state) {
if (mDetailRecord == r) {
fireToggleStateChanged(state);
}
}
@Override
public void onScanStateChanged(boolean state) {
r.scanState = state;
if (mDetailRecord == r) {
fireScanStateChanged(r.scanState);
}
}
@Override
public void onAnnouncementRequested(CharSequence announcement) {
announceForAccessibility(announcement);
}
};
r.tile.setCallback(callback);
final View.OnClickListener click = new View.OnClickListener() {
@Override
public void onClick(View v) {
if(sSupportBtWifiSoftApCoexist.equals("false")){
if(v.getId() == BLUETOOTH_VIEW_ID){
mTimeStart = System.currentTimeMillis();
}
if(v.getId() == HOTSPOT_VIEW_ID && (System.currentTimeMillis() - mTimeStart) < 500){
return;
}
if(v.getId() == AIRPLANE_VIEW_ID){
mAirTimeStart = System.currentTimeMillis();
}
if(v.getId() == HOTSPOT_VIEW_ID && (System.currentTimeMillis() - mAirTimeStart) < 800){
return;
}
}
r.tile.click();
}
};
final View.OnClickListener clickSecondary = new View.OnClickListener() {
@Override
public void onClick(View v) {
r.tile.secondaryClick();
}
};
final View.OnLongClickListener longClick = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
r.tile.longClick();
return true;
}
};
r.tileView.init(click, clickSecondary, longClick);
r.tile.setListening(mListening);
callback.onStateChanged(r.tile.getState());
r.tile.refreshState();
mRecords.add(r);
addView(r.tileView);
}
QSPanel.java中的addTile()方法最终调用了addView()方法将tile添加到QSPanel这个viewgroup中。在添加进去前先对它初始化。
3、mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
4、qsh.setCallback();//注册Tiles发生改变时回调onTiles。
那么quick settings tile panel的加载就分析到这里了。