SystemUI 下拉框自定义(AN 9.0)

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342