前几天刷了一个9.0的供应商代码,赶紧来看看9.0的设置中蓝牙搞成了什么样子?

在研究源码时我一般喜欢从UI着手。因为UI会告诉你都有哪些功能。要不然直接看源码真是无从下手。

蓝牙菜单没有了已经,替换成了已连接的设备的菜单,界面如下

Android9.0源码分析----设置中蓝牙架构初步分析_java

从界面上来看,总共有六大部分

  1. 可用的媒体/通话设备:可用的媒体设备是指支持a2dp的设备,可用的通话设备是指支持hsp的设备。当设备列表为空时,隐藏该preferencegroup

  2. 当前已连接:usb连接属于,以及其他非a2dp和hsp的蓝牙连接设备比如无线鼠标、键盘等,还有无线充电座。当设备列表为空时,隐藏该preferencegroup

  3. 与新设备配对:点击后进入蓝牙扫描界面,该界面中可以修改本机
    蓝牙名称,扫描附近可用设备。点击Preference时,当蓝牙未开启时自动开启蓝牙

  4. 之前连接的设备:相当于已配对蓝牙设备列表,排除掉当前已连接的设备。当蓝牙关闭时该preference无法点击

  5. 连接偏好设置:包括蓝牙、nfc、投屏、打印等设置,这里直接跳入蓝牙设置,包含了蓝牙的开关、本机蓝牙名称修改、与新设备配对三个功能

  6. 向其他设备显示为“...”

在当前已连接的设备列表中发现了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控制哪些方面呢?

  1. 是否显示:如果设备不支持或者是列表为空就不显示

  2. 是否available:preference会显示出来,但是可能不可点击,比如蓝牙关闭时,“之前连接的设备”这个preference会显示出来,但是却被disable掉,不可点击。也就是说设备本身是支持的,但因为某些设置,导致当前设置不可用

  3. 更新title和summary:比如可用的媒体设备会有两个标题,一个是媒体设备,一个是通话设备,这个就是通过在controller进行一些判断来显示的

  4. 更新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函数

  1. 注册BluetoothCallback函数,用于更新Bluetooth设备相关的一些状态改变。

  2. 提供函数用来注册DevicePreferenceCallback函数

来一张图大致看一下代码的大致构建

Android9.0源码分析----设置中蓝牙架构初步分析_java_02

 

图画的还算很详细了,可以对着大图来分析源码,图有些大,建议在电脑端查看。

接下来来分析下图

  1. 红色部分是主界面(已连接的设备界面)所对应的controller的值

  2. 蓝色部分是各个Preference点击后要跳转的二级fragment

  3. 绿色部分表示的是各个controller所init的updater

可以看到每个Preference都有对应的controller:因为要更新管理Preference

与新设备配对Preference有fragment,因为要跳转到扫描界面

之前连接的设备Preference有fragment,因为要跳转到已配对设备列表

连接偏好设置Preference有fragment,因为要跳转到一系列的设置

Android9.0源码分析----设置中蓝牙架构初步分析_java_03

可用媒体设备、当前已连接的设备、之前连接的设备三个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