com.android.systemui.statusbar.phone.StatusBar.java
该文件布局文件为R.layout.status_bar_expanded,其中包含了statusBar的布局
创建绑定QSFragment.java
// Set up the quick settings tile panel View container = mStatusBarWindow.findViewById(R.id.qs_frame); if (container != null) { FragmentHostManager fragmentHostManager = FragmentHostManager.get(container); ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame, Dependency.get(ExtensionController.class) .newExtension(QS.class) .withPlugin(QS.class) .withDefault(this::createDefaultQSFragment) .build()); mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow, (visible) -> { mBrightnessMirrorVisible = visible; updateScrimController(); }); fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> { QS qs = (QS) f; if (qs instanceof QSFragment) { mQSPanel = ((QSFragment) qs).getQsPanel(); mQSPanel.setBrightnessMirror(mBrightnessMirrorController); } }); }
R.layout.qs_pannel即是你要找的布局,而其中QSPannel.java类就是一个自定义view,这就需要在这里面添加东西
在QSFragment.java中就定义了头部中间部分和尾部
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mQSPanel = view.findViewById(R.id.quick_settings_panel); mQSDetail = view.findViewById(R.id.qs_detail); mHeader = view.findViewById(R.id.header); mFooter = view.findViewById(R.id.qs_footer); mContainer = view.findViewById(id.quick_settings_container); mQSDetail.setQsPanel(mQSPanel, mHeader, (View) mFooter); mQSAnimator = new QSAnimator(this, mHeader.findViewById(R.id.quick_qs_panel), mQSPanel); mQSCustomizer = view.findViewById(R.id.qs_customize); mQSCustomizer.setQs(this); if (savedInstanceState != null) { setExpanded(savedInstanceState.getBoolean(EXTRA_EXPANDED)); setListening(savedInstanceState.getBoolean(EXTRA_LISTENING)); setEditLocation(view); mQSCustomizer.restoreInstanceState(savedInstanceState); if (mQsExpanded) { mQSPanel.getTileLayout().restoreInstanceState(savedInstanceState); } } setHost(mHost); }
这里是QSFragment控制展开还是不展开的状态控制
然后我们就可以去QSPannel.java类中看其展开的状态
其中就有一个PagedTileLayout类,这是一个继承与ViewPager的自定义view,所以展开选项一般分几个界面,其中就需要进里面查看这个对象mTileLayout如何初始化的了,其中选中其中adapte中的数据TilePage类mPages
这就发现实际加载的界面布局为 com.android.systemui.qs.PagedTileLayout.TilePage该类
其中就发现该对象的添加数据对象是TileRecord这个类,响应事件应该是com.android.systemui.qs.QSPanel.QSTileLayout这个接口实现的,然后我们在返回去,查看是哪里的数据加载了这个界面
发现还是查看com/android/systemui/qs/PagedTileLayout.java这个文件中的mPages,而这个加载又指向了其中的mTiles,所以只需要找这个数据是谁给的就行了
之后发现是QSPannel.java类中的addTile()方法添加的TileRecord对象
此时就有两个一个是QSTile.java这个是数据对象,另一个是QSTileView.java这个是UI对象,先现就一下UI对象QSTileView,
从而跳转到了QSTileHost.java中,
之后具体实现在QSFactoryImpl.java中,然而这两种情况,都指向了QSTileBaseView.java中的构造函数
其中QSTileBaseView.java中
所以这个又转回QSIconView中,而QSIconView是个abstract类,转向了QSIconViewImpl.java类中
其中QSPannel.java中的数据指向
其中这个setTiles在com/android/systemui/qs/QuickQSPanel.java类中以及QSPannel.java类中都指向QSTileHost的mHost对象了,这就需要找mHost的getTiles中赋值在哪了
从而在QSTileHost.java中发现,其中的值来自mTiles,而这个mTiles中的赋值只有一处
就是在QSTileHost.java中的onTuningChanged()函数中,而这个函数调用实现是在TunerServiceImpl.java中的addTunable调用的,到这就可以结束了,这个onTuningChanged是通知
这边刷新UI的,具体就看QSTileHost这里的onTuningChanged内容;
这里有两个关键的方法,一个是获取config里面的字符串信息,
一个是实例化Tile的creatTile(titleSpecs)
然后指向QSFactoryImpl.java对象中的createTile()
最后根据字符串实例化对象
所以添加QSTile就只需要添加对应字符串,然后添加对应对象实例化就行;
到这就应该如何添加自定义QSTile按键了,然后如何自定义案件的布局就需要找到对应控件了,
其中在com/android/systemui/qs/TileLayout.java中的layoutTileRecords()方法中就有添加单独对象的方法
从这里看出,就是将之前添加中TileRecord对象里面的tileView自定义就行,而这个tileView创建就在之前提及的QSFactoryImpl.java中
从而自定义布局就是更改这个QSTileBaseView的布局,而这个QSTileBaseView中添加了一个QSIconView,更改这个就可以达到目的了,
而这个QSIconView更改只覆盖掉QSTileImpl中的createTileView()返回的QSIconView对象就行,所以要在自定义继承QSTileImpl类中重写createTileView()方法就行,其中可以参考com/android/systemui/qs/SignalTileView.java方式重写。
adb shell settings get secure sysui_qs_tiles
可以查看实际qs_tiles读取的字符串,这样子看实际有没有更改加载到内容