前几天刷了一个9.0的供应商代码,赶紧来看看9.0的设置中蓝牙搞成了什么样子?
在研究源码时我一般喜欢从UI着手。因为UI会告诉你都有哪些功能。要不然直接看源码真是无从下手。
蓝牙菜单没有了已经,替换成了已连接的设备的菜单,界面如下
从界面上来看,总共有六大部分
-
可用的媒体/通话设备:可用的媒体设备是指支持a2dp的设备,可用的通话设备是指支持hsp的设备。当设备列表为空时,隐藏该preferencegroup
-
当前已连接:usb连接属于,以及其他非a2dp和hsp的蓝牙连接设备比如无线鼠标、键盘等,还有无线充电座。当设备列表为空时,隐藏该preferencegroup
-
与新设备配对:点击后进入蓝牙扫描界面,该界面中可以修改本机
蓝牙名称,扫描附近可用设备。点击Preference时,当蓝牙未开启时自动开启蓝牙 -
之前连接的设备:相当于已配对蓝牙设备列表,排除掉当前已连接的设备。当蓝牙关闭时该preference无法点击
-
连接偏好设置:包括蓝牙、nfc、投屏、打印等设置,这里直接跳入蓝牙设置,包含了蓝牙的开关、本机蓝牙名称修改、与新设备配对三个功能
-
向其他设备显示为“...”
在当前已连接的设备列表中发现了usb的身影。在连接偏好设置中发现了nfc
初步来看的话9.0源码应该是将usb、nfc、bt等可连接的设备整合到了一起。整合成了已连接设备
这个改动还是很良心的,用户可以清晰的看到手机连接了哪些设备。把所有相似的东西整合到一起。
省的再去一个个的找该设备究竟还有没有和其他设备有连接
靠着以前对6.0源码的Settings分析的基础,定位该界面的fragment:
找到settings应用的Androidmanifest.xml文件。
找到声明的BluetoothSettingsActivity。可以看到其所对应的fragment,ConnectedDeviceDashboardFragment,fragment所对应的xml为connected_devices.xml
看一下这个fragment代码,乍一看可能会很懵,会发现出现了很多以前未出现的类比如BasePreferenceController,DevicePreferenceCallback,BluetoothDeviceUpdater之类的。
全是一堆没见过的东西。
莫慌,google大佬这是在优化整合连接设备相关的这个代码架构。
但甭管怎么优化,核心功能不会变,一是对Preference的更新和控制,再一个就是对Preference中列表的更新和控制
在connected_devices.xml中可以看到每个preference都有一个controller属性。但有的Preference有fragment属性,有的Preference没有fragment属性这是为什么?
首先,明确这个fragment是用来干嘛的?是在点击preference时默认要跳转的fragment
这个controller是干嘛用的?是用来控制preference的显示的.
这样就很好的解释了为什么所有的Preference都有controller属性,而fragment属性却是option可选项
那么controller控制哪些方面呢?
-
是否显示:如果设备不支持或者是列表为空就不显示
-
是否available:preference会显示出来,但是可能不可点击,比如蓝牙关闭时,“之前连接的设备”这个preference会显示出来,但是却被disable掉,不可点击。也就是说设备本身是支持的,但因为某些设置,导致当前设置不可用
-
更新title和summary:比如可用的媒体设备会有两个标题,一个是媒体设备,一个是通话设备,这个就是通过在controller进行一些判断来显示的
-
更新Preferencegroup的列表:比如可用的媒体设备列表的更新
那么DevicePreferenceCallback是干嘛使的呢?
先去看一下接口的定义
1/**
2 * Callback to add or remove {@link Preference} in device group.
3 */
4public interface DevicePreferenceCallback {
5 /**
6 * Called when a device(i.e. bluetooth, usb) is added
7 * @param preference present the device
8 */
9 void onDeviceAdded(Preference preference);
10
11 /**
12 * Called when a device(i.e. bluetooth, usb) is removed
13 * @param preference present the device
14 */
15 void onDeviceRemoved(Preference preference);
16}
就俩方法我滴个乖乖,想都不敢想他能如此简单。
这俩方法就是用来更新和当前界面相关的Preference和Preferencegroup列表的
那么BluetoothDeviceUpdater干啥用的呢?该updater实现了BluetoothCallback函数
-
注册BluetoothCallback函数,用于更新Bluetooth设备相关的一些状态改变。
-
提供函数用来注册DevicePreferenceCallback函数
来一张图大致看一下代码的大致构建
图画的还算很详细了,可以对着大图来分析源码,图有些大,建议在电脑端查看。
接下来来分析下图
-
红色部分是主界面(已连接的设备界面)所对应的controller的值
-
蓝色部分是各个Preference点击后要跳转的二级fragment
-
绿色部分表示的是各个controller所init的updater
可以看到每个Preference都有对应的controller:因为要更新管理Preference
与新设备配对Preference有fragment,因为要跳转到扫描界面
之前连接的设备Preference有fragment,因为要跳转到已配对设备列表
连接偏好设置Preference有fragment,因为要跳转到一系列的设置
可用媒体设备、当前已连接的设备、之前连接的设备三个controller实现了DevicePreferenceCallback。
可用媒体设备和当前已连接的设备实现这个callback很好理解,因为要显示设备列表。并对列表项进行增加和删除
那么之前连接的设备这个Preference为什么要实现callback呢?是为了计算列表项数,每次onDeviceAdded时,size++,每次onDeviceRemoved时,size--。size为0时,要disable掉Preference(这个逻辑是在controller中实现的).
因为这三个的controller实现了callback,为了让callback起作用,他们必须要初始化BluetoothDeviceUpdater,来激活也就是来注册DevicePreferenceCallback(是通过controller的init方法创建updater实例实现的)
到这儿就会有个问题,从那个代码架构图中可以很清晰的看到
可用的媒体设备的controller已经init了一个BluetoothUpdater,因为updater实现了BluetoothCallback,按道理来讲只需要在updater中监听btCallback的回调即可,为什么controller又要实现一次callback呢?
这是因为updater用于更新具体的device也就是Preferencegroup中的列表,controller用于更新Preferencegroup的标题和summary。
在连接到a2dp/hsp时,设备是一个,是可用的媒体设备
当来电时,设备是一个,是可用的通话设备
所以此时单从DevicePreferenceCallback的角度是没办法来修改PreferenceGroup的title的,只能依靠BtCallback的onAudioModeChanged方法。
本文相当于拎出个大致的框架,具体出问题时还需要具体分析
比如,如果已连接的设备主界面中各个部分的标题或者状态显示有问题,则去修改对应的controller文件
如果遇到已连接的设备主界面中各个部分的列表项显示有问题,则要去查看对应的updater
相信很少人能坚持像你一样看到结尾了,你竟如此优秀,祝元宵节快乐~
https://mp.weixin.qq.com/s/OklqOKiL6AAa-LFCK9i8KQ