1 dump 出ui 布局
uiautomator dump
以sound 为例找出其ui布局节点如下:
... ... ... ...
text="Sound" resource-id="com.android.systemui:id/tile_label" class="android.widget.TextView" package="com.android.systemui" content-desc=""
... ... ... ...
2 从代码找出相关布局元素
很明显包名为SystemUI 因此去frameworks/base/packages/SystemUI 下查询tile_label,得:
./src/com/android/systemui/qs/tileimpl/QSTileView.java:85: .inflate(R.layout.qs_tile_label, this, false);
./src/com/android/systemui/qs/tileimpl/QSTileView.java:88: mLabel = mLabelContainer.findViewById(R.id.tile_label);
./src/com/android/systemui/qs/customize/TileAdapter.java:272: R.string.accessibility_qs_edit_add_tile_label, info.state.label);
./src/com/android/systemui/qs/customize/TileAdapter.java:278: R.string.accessibility_qs_edit_tile_label, position + 1, info.state.label);
./src/com/android/systemui/qs/customize/TileAdapter.java:449: mTileView.findViewById(R.id.tile_label).clearAnimation();
./src/com/android/systemui/qs/customize/TileAdapter.java:450: mTileView.findViewById(R.id.tile_label).setAlpha(1);
./src/com/android/systemui/qs/customize/TileAdapter.java:460: mTileView.findViewById(R.id.tile_label).animate()
./src/com/android/systemui/qs/customize/TileAdapter.java:473: mTileView.findViewById(R.id.tile_label).animate()
分析相关代码添加逻辑:
由此可知该元素很可能叫做:QSTileView
实际查看代码定义也确实如此:
public class QSTileView extends QSTileBaseView {
private static final int MAX_LABEL_LINES = 2;
private static final boolean DUAL_TARGET_ALLOWED = false;
private View mDivider;
protected TextView mLabel;
protected TextView mSecondLine;
private ImageView mPadLock;
private int mState;
private ViewGroup mLabelContainer;
private View mExpandIndicator;
private View mExpandSpace;
3 查找QSTileView 的调用
./tests/src/com/android/systemui/qs/TileLayoutTest.java:38:import com.android.systemui.qs.tileimpl.QSTileView;
./tests/src/com/android/systemui/qs/TileLayoutTest.java:63: tileRecord.tileView = spy(new QSTileView(mContext, new QSIconViewImpl(mContext)));
./plugin/src/com/android/systemui/plugins/qs/QSFactory.java:27:@DependsOn(target = QSTileView.class)
./plugin/src/com/android/systemui/plugins/qs/QSFactory.java:34: QSTileView createTileView(QSTile tile, boolean collapsedView);
./plugin/src/com/android/systemui/plugins/qs/QSTileView.java:25:@ProvidesInterface(version = QSTileView.VERSION)
./plugin/src/com/android/systemui/plugins/qs/QSTileView.java:28:public abstract class QSTileView extends LinearLayout {
./plugin/src/com/android/systemui/plugins/qs/QSTileView.java:31: public QSTileView(Context context) {
./src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java:24:import com.android.systemui.plugins.qs.QSTileView;
./src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java:120: public QSTileView createTileView(QSTile tile, boolean collapsedView) {
./src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java:126: return new com.android.systemui.qs.tileimpl.QSTileView(context, icon);
./src/com/android/systemui/qs/tileimpl/QSTileView.java:38:public class QSTileView extends QSTileBaseView {
./src/com/android/systemui/qs/tileimpl/QSTileView.java:50: public QSTileView(Context context, QSIconView icon) {
./src/com/android/systemui/qs/tileimpl/QSTileView.java:54: public QSTileView(Context context, QSIconView icon, boolean collapsedView) {
./src/com/android/systemui/qs/tileimpl/QSTileBaseView.java:46:public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView {
./src/com/android/systemui/qs/tileimpl/QSTileBaseView.java:71: // Default to Quick Tile padding, and QSTileView will specify its own padding.
./src/com/android/systemui/qs/QSPanel.java:43:import com.android.systemui.plugins.qs.QSTileView;
./src/com/android/systemui/qs/QSPanel.java:416: protected QSTileView createTileView(QSTile tile, boolean collapsedView) {
./src/com/android/systemui/qs/QSPanel.java:601: QSTileView getTileView(QSTile tile) {
./src/com/android/systemui/qs/QSPanel.java:652: public com.android.systemui.plugins.qs.QSTileView tileView;
./src/com/android/systemui/qs/customize/CustomizeTileView.java:23:import com.android.systemui.qs.tileimpl.QSTileView;
./src/com/android/systemui/qs/customize/CustomizeTileView.java:25:public class CustomizeTileView extends QSTileView {
./src/com/android/systemui/qs/QuickQSPanel.java:32:import com.android.systemui.plugins.qs.QSTileView;
./src/com/android/systemui/qs/QuickQSPanel.java:277: private int getChildIndex(QSTileView tileView) {
./src/com/android/systemui/qs/QSTileHost.java:36:import com.android.systemui.plugins.qs.QSTileView;
./src/com/android/systemui/qs/QSTileHost.java:293: public QSTileView createTileView(QSTile tile, boolean collapsedView) {
./src/com/android/systemui/qs/QSTileHost.java:295: QSTileView view = mQsFactories.get(i).createTileView(tile, collapsedView);
./src/com/android/systemui/qs/QSAnimator.java:25:import com.android.systemui.plugins.qs.QSTileView;
./src/com/android/systemui/qs/QSAnimator.java:177: QSTileView tileView = mQsPanel.getTileView(tile);
./src/com/android/systemui/qs/QSAnimator.java:186: QSTileView quickTileView = mQuickQsPanel.getTileView(tile);
从createTileView 方法查看:
./plugin/src/com/android/systemui/plugins/qs/QSFactory.java:34: QSTileView createTileView(QSTile tile, boolean collapsedView);
./plugin/src/com/android/systemui/plugins/qs/QSTile.java:53: QSIconView createTileView(Context context);
./src/com/android/systemui/qs/tileimpl/QSTileImpl.java:138: public QSIconView createTileView(Context context) {
./src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java:120: public QSTileView createTileView(QSTile tile, boolean collapsedView) {
./src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java:122: QSIconView icon = tile.createTileView(context);
./src/com/android/systemui/qs/QSPanel.java:416: protected QSTileView createTileView(QSTile tile, boolean collapsedView) {
./src/com/android/systemui/qs/QSPanel.java:417: return mHost.createTileView(tile, collapsedView);
./src/com/android/systemui/qs/QSPanel.java:427: r.tileView = createTileView(tile, collapsedView);
./src/com/android/systemui/qs/QSTileHost.java:293: public QSTileView createTileView(QSTile tile, boolean collapsedView) {
./src/com/android/systemui/qs/QSTileHost.java:295: QSTileView view = mQsFactories.get(i).createTileView(tile, collapsedView);
./src/com/android/systemui/qs/tiles/WifiTile.java:108: public QSIconView createTileView(Context context) {
./src/com/android/systemui/qs/tiles/CellularTile.java:95: public QSIconView createTileView(Context context) {
定位到顶层调用
./src/com/android/systemui/qs/QSPanel.java:416
protected QSTileView createTileView(QSTile tile, boolean collapsedView) {
return mHost.createTileView(tile, collapsedView);
}
protected boolean shouldShowDetail() {
return mExpanded;
}
protected TileRecord addTile(final QSTile tile, boolean collapsedView) {
final TileRecord r = new TileRecord();
r.tile = tile;
r.tileView = createTileView(tile, collapsedView);
再定位addTile
./tests/src/com/android/systemui/qs/TileLayoutTest.java:70: mTileLayout.addTile(tileRecord);
./tests/src/com/android/systemui/qs/TileLayoutTest.java:77: mTileLayout.addTile(tileRecord);
./tests/src/com/android/systemui/qs/TileLayoutTest.java:85: mTileLayout.addTile(tileRecord);
./tests/src/com/android/systemui/qs/TileLayoutTest.java:94: mTileLayout.addTile(tileRecord);
./tests/src/com/android/systemui/qs/TileLayoutTest.java:102: mTileLayout.addTile(tileRecord);
./tests/src/com/android/systemui/qs/TileLayoutTest.java:112: mTileLayout.addTile(tileRecord1);
./tests/src/com/android/systemui/qs/TileLayoutTest.java:113: mTileLayout.addTile(tileRecord2);
./tests/src/com/android/systemui/qs/TileLayoutTest.java:122: mTileLayout.addTile(tileRecord);
./tests/src/com/android/systemui/qs/TileLayoutTest.java:132: mTileLayout.addTile(tileRecord1);
./tests/src/com/android/systemui/qs/TileLayoutTest.java:133: mTileLayout.addTile(tileRecord2);
./tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java:63: verify(mQsTileHost).addTile("night");
./tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java:72: verify(mQsTileHost, never()).addTile("night");
./tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java:82: verify(mQsTileHost).addTile("night");
./tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java:92: verify(mQsTileHost).addTile("night");
./tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java:102: verify(mQsTileHost, never()).addTile("night");
./src/com/android/systemui/qs/PagedTileLayout.java:162: public void addTile(TileRecord tile) {
./src/com/android/systemui/qs/PagedTileLayout.java:227: mPages.get(index).addTile(tile);
./src/com/android/systemui/qs/QSPanel.java:408: addTile(tile, collapsedView);
./src/com/android/systemui/qs/QSPanel.java:424: protected TileRecord addTile(final QSTile tile, boolean collapsedView) {
./src/com/android/systemui/qs/QSPanel.java:473: mTileLayout.addTile(r);
./src/com/android/systemui/qs/QSPanel.java:658: void addTile(TileRecord tile);
./src/com/android/systemui/qs/QSTileRevealController.java:30: addTileSpecsToRevealed(mTilesToReveal);
./src/com/android/systemui/qs/QSTileRevealController.java:62: addTileSpecsToRevealed(tileSpecs);
./src/com/android/systemui/qs/QSTileRevealController.java:70: private void addTileSpecsToRevealed(ArraySet<String> specs) {
./src/com/android/systemui/qs/customize/TileQueryHelper.java:111: addTile(tile.getTileSpec(), null, state, true);
./src/com/android/systemui/qs/customize/TileQueryHelper.java:138: addTile(spec, appLabel, state, false);
./src/com/android/systemui/qs/customize/TileQueryHelper.java:154: addTile(spec, icon, label != null ? label.toString() : "null", appLabel);
./src/com/android/systemui/qs/customize/TileQueryHelper.java:178: private void addTile(String spec, CharSequence appLabel, State state, boolean isSystem) {
./src/com/android/systemui/qs/customize/TileQueryHelper.java:195: private void addTile(
./src/com/android/systemui/qs/customize/TileQueryHelper.java:201: addTile(spec, appLabel, state, false);
./src/com/android/systemui/qs/QuickQSPanel.java:242: public void addTile(TileRecord tile) {
./src/com/android/systemui/qs/QSTileHost.java:236: public void addTile(String spec) {
./src/com/android/systemui/qs/QSTileHost.java:248: public void addTile(ComponentName tile) {
./src/com/android/systemui/qs/TileLayout.java:56: public void addTile(TileRecord tile) {
./src/com/android/systemui/statusbar/phone/StatusBar.java:1459: mQSPanel.getHost().addTile(tile);
./src/com/android/systemui/statusbar/phone/AutoTileManager.java:71: mHost.addTile(INVERSION);
./src/com/android/systemui/statusbar/phone/AutoTileManager.java:105: mHost.addTile(WORK);
./src/com/android/systemui/statusbar/phone/AutoTileManager.java:124: mHost.addTile(SAVER);
./src/com/android/systemui/statusbar/phone/AutoTileManager.java:137: mHost.addTile(HOTSPOT);
./src/com/android/systemui/statusbar/phone/AutoTileManager.java:165: mHost.addTile(NIGHT);
找到
./src/com/android/systemui/qs/QSTileHost.java:236
public void addTile(String spec) {
final String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
TILES_SETTING, ActivityManager.getCurrentUser());
final List<String> tileSpecs = loadTileSpecs(mContext, setting);
if (tileSpecs.contains(spec)) {
return;
}
tileSpecs.add(spec);
Settings.Secure.putStringForUser(mContext.getContentResolver(), TILES_SETTING,
TextUtils.join(",", tileSpecs), ActivityManager.getCurrentUser());
}
public void addTile(ComponentName tile) {
List<String> newSpecs = new ArrayList<>(mTileSpecs);
newSpecs.add(0, CustomTile.toSpec(tile));
changeTiles(mTileSpecs, newSpecs);
}
此处我们已经知道可以通过设置得到下拉菜单得设置了:
settings get secure TILES_SETTING
我手机:
settings get secure sysui_qs_tiles
WIFI,DATA,BLUETOOTH,NFC,SOUND,ROTATION,FLASHLIGHT,AIRPLANE,SYNC,HOTSPOT,QMEMO,BATTERY_SAVER,LOCATION,DO_NOT_DISTURB,DATA_SAVER
查看final List<String> tileSpecs = loadTileSpecs(mContext, setting);:
protected List<String> loadTileSpecs(Context context, String tileList) {
final Resources res = context.getResources();
final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
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;
}
由上可知修改出厂默认下拉框元素可以修改xml文件
quick_settings_tiles_default
quick_settings_tiles
4 进阶
三方应用下拉框设置查询如下:
settings get secure sysui_qs_tiles
WIFI,DATA,BLUETOOTH,NFC,SOUND,ROTATION,FLASHLIGHT,AIRPLANE,SYNC,HOTSPOT,QMEMO,BATTERY_SAVER,LOCATION,DO_NOT_DISTURB,DATA_SAVER,custom(com.google.android.gms/.nearby.sharing.SharingTileService)
显然,实现TileService 即可
https://developer.android.com/reference/android/service/quicksettings/TileService