当前位置: 首页 > news >正文

android 蓝牙源码分析

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

BluetoothService类中定义的Native方法都在android_server_BluetoothServer.cpp里建立jni调用

一、开启(BT Turn on Turn off) (蓝牙的打开关闭由类BluetoothEnabler控制。)

1.由BluetoothEnabler控制界面操作,在其构造函数里会先调用 LocalBluetoothManager.getInstance(context)。

2.然后在LocalBluetoothManager类的getInstance函数里会调用当前类下的init()函数,该init()函数中通过BluetoothAdapter.getDefaultAdapter()获得蓝牙设备的句柄,如果当前没有蓝牙设备则返回null。 

3.初始化完毕会监听checkbox的状态,当触发点击checkbox会响应onPreferenceChange方法,其中将调用 LocalBluetoothManager.setBluetoothEnabled(enable)方法。

而LocalBluetoothManager.setBluetoothEnabled(enable)方法,会调用mAdapter.enable()方法,enable()方法又会调用 BluetoothService.enable()方法。其中,

(1)打开(关闭)操作成功后会有一个异步事件ACTION_STATE_CHANGED返回,异步事件由类BluetoothEventRedirector控制(接收广播,进行处理)。在收到ACTION_STATE_CHANGED异步事件后,还需要做update本地设备profile的事情,读取上次关闭前搜索到的蓝牙设备。

(1.1)update本地设备profile的事情:?

(1.2)读取上次关闭前搜索到的蓝牙设备:

通过LocalBluetoothManager.setBluetoothStateInt(int state)方法调到 CachedBluetoothDeviceManager.onBluetoothStateChanged方法来读取上次关闭之前搜索到device. 

(2)来开启EnableThread线程,进行打开操作,蓝牙的打开关闭属于异步操作。

ps:在启动蓝牙的时候,要注意的地方是不能正常启动蓝牙的情况,因为正常启动的时候会返回BluetoothIntent.ENABLED_ACTION 这个Intent,当时当启动出现异常的时候是没有Intent返回的,android使用回调函数来解决这个问题。下面是在bluetoothdeviceservice.java 里面enable(IBluetoothDeviceCallback callback 的过程:(以下代码属于较低版本的android源码,与较高版本源码中已有所不同,只作为参考...)

View Code

 

 

涉及到的类: 

BluetoothService(最主要的类,开启具体命令的线程进行enable,disable等操作) 
LocalBluetoothManager(本机蓝牙设备管理,开启关闭,搜索等等,初始化BluetoothAdapter) 
BluetoothEnabler(界面的点击和状态文字的显示) 
BluetoothAdapter(framework封装的类,提供本地蓝牙设备的配置,包括开启蓝牙,搜索周围蓝牙设备,设置本地蓝牙可见性;建立LocalBluetoothManager和BluetoothService的映射关系,主要是通过它调用BluetoothService的函数)

BluetoothEventRedirector(接收Bluetooth API 的广播和回调,并且将Settings中的UI线程上的事件分派到正确的类)

 

二、可检测性(Discoverable)

1.蓝牙的discoverable mode由类BluetoothDiscoverableEnabler控制。点击将触发OnPreferenceChangeListener监听事件,调用onPreferenceChange()方法,该方法中调用setEnabled(true),而setEnabled(true)方法将调用到BluetoothAdapter的setScanMode () 方法。

蓝牙模式有两种模式SCAN_MODE_CONNECTABLE_DISCOVERABLE(可连接可发现)和SCAN_MODE_CONNECTABLE(可连接但不可发现)

 
涉及到的类: 
LocalBluetoothManager 
BluetoothDiscoverableEnabler 
BluetoothAdapter

 

三、扫描 

1.在BluetoothSetting里触发点击,调用LocalBluetoothManager.startScanning(true)函数,通过BluetoothAdapter的startDiscovery调用到BluetoothService里的startDiscovery来调用Native函数 startDiscoveryNative()。 

startDiscovery()是个异步函数,会立即返回,通过注册 ACTION_DISCOVERY_STARTED、ACTION_DISCOVERY_FINISHED、ACTION_FOUND,来确定当前的状态。 

当蓝牙由disable变成enable时会调用扫描,当距离上次扫描超过5分钟的前提下,退出页面,再进到页面的时候也会启动扫描。 

在启动scan的时候,还会判断当前是否在播放音乐,如果在播放音乐,则不启动扫描。 

点击查找设备后,会把设备列表里没有配对的设备清除掉,保留配对状态的设备。

扫描的过程是一个很耗费资源的过程,在扫描过程,不会去尝试进行新的连接,扫描时间默认是12秒,它是以一个系统服务的形式存在的,可以调用cancelDiscovery()来取消扫描。 

 

四、连接 

1.1 在setting界面点击连接,会调到CachedBluetoothDevice类的connect方法。

1.2 而connect方法会调用connectWithoutResettingTimer()方法。

1.3 而connectWithoutResettingTimer()方法会调用 connectInt方法。

在connectInt里,根据不同的profile来获得profilemanger,然后调用 profilemanger.connect()函数 。此处的链接会涉及到的profile有A2DP AVRCP DUN HSP HFP 等。

同理如果配对或者解除配对,也会调到CachedBluetoothDevice类的pair()方法和unpair()。

 

以A2DP为例,在connectInt里,根据不同的profile来获得profilemanger,然后调用 profilemanger.connect()函数,在这个函数里调用了BluetoothA2dpService的connectSink()函数,最后调到Native方法

connectSinkNative()去建立连接。 

涉及到的一些类: 

CachedBluetoothDevice(搜索到的设备) 
BluetoothDevice(设备类) 
LocalBluetoothProfileManager(是一个抽象类,各种ProfileManger,实例化各种Profile的service) 
SettingsBtStatus(蓝牙的状态类) 
BluetoothA2dp(为LocalBluetoothProfileManager和BluetoothA2dpService建立映射关系) 
BluetoothA2dpService(最终的服务类,由它调用连接、断开等Native函数,和底层通信)

 

其他文件作用(接收与发送类似)

1.BluetoothOppReceiver.java 这个类里描述的是蓝牙传输文件过程中接收到的广播事件。

2.BluetoothOppTransfer.java 管理文件传输的类

3. BluetoothOppService.java 蓝牙传输文件后台的类

4. BluetoothOppObexClientSession.java 具体实现文件传输的类

 

 

?
通过源码分析蓝牙执行过程:(Bluetooth--->BT)
?
1、开启
 
步骤1:首先从BTSettings开始,执行onCreate方法。因为是初始化状态,所以if(action.equal(BTDevicePicker.ACTION_LAUNCH))不满足,故执行else语句。
 
步骤2:初始化mEnable对象,调用BTEnable构造函数。通过LocalBTManager.getInstance调用init方法,再通过init方法调用BTAdapter.getDefaultAdapter()获得适配器句柄。
 
步骤3:各种初始化完毕后,执行BTSettings中的onResume方法,调用BTEnabler.resume方法,该resume方法为组合框设置监听事件。
 
步骤4:当蓝牙开启时,该组合框被选中,将响应监听事件,执行BTEnabler.onPreferenceChange方法。该方法中会调用LocalBTManager.setBTEnabled方法。而setBTEnabled方法会调用BTAdapter.enable()方法,继而调用BTService.enable()方法,继而调用BTService.enable(true)方法。在该方法中,
 
(1)当enable(true)方法返回true时,在setBTEnabled方法中会调用BTService中的setBTStateInt方法,继而广播出去,由BTEventRedirector类接收。
 
(2)开启新的线程,主要的启动过程是放在这个新启动的线程里面。
 
(3)开启蓝牙后,会调用CachedBTDeviceManager.onBTStateChanged方法来读取上次关闭前搜索到的蓝牙设备。
 
2.可检测的
 
点击“可检测性”组合框,将触发BTDiscoverableEnabler.onPreferenceChange方法,然后调用同个类中的setEnabled方法,来调用BTAdapter.setScanMode方法(其中传递SCAN_MODE_CONNECTABLE_DISCOVERABLE参数),继而会调用BTService.setScanMode方法,在该方法中,会通过setDiscoverableTimeout方法设置检测时间。
 
3.扫描
 
BTSettings的onResume方法继续往下运行,将调用LocalBTManager.startScanning方法,该方法会调用BTAdapter.startDiscovery方法,继而调用BTService.startDiscovery方法,再调用startDIscoveryNative方法。
 
4.连接
 
步骤1:在setting界面点击连接,会调到CachedBluetoothDevice类的connect方法。
 
步骤2:而connect方法会调用connectWithoutResettingTimer()方法。
 
步骤3:而connectWithoutResettingTimer()方法会调用 connectInt方法。
 
步骤4:在connectInt里,根据不同的profile来获得profilemanger,然后调用 profilemanger.connect()函数 。此处的链接会涉及到的profile有A2DP AVRCP DUN HSP HFP 等。
 
同理如果配对或者解除配对,也会调到CachedBluetoothDevice类的pair()方法和unpair()。

转载于:https://my.oschina.net/u/994235/blog/113186

相关文章:

  • 新版本的GNS3(0.8.2)模拟ASA的教程
  • LVM的综合性介绍及实现
  • (实战篇)如何缓存数据
  • android 抓包分析
  • 从外形如何分辨iTouch是几代的?
  • Word中使用正则表达式进行查找和替换
  • 打开Windows2008 R2 Server Manager或执行Windows Update时出现0x800F0818错误
  • 针对11.2 RAC丢失OCR和Votedisk所在ASM Diskgroup的恢复手段
  • Linux 获取CPU温度
  • OpenCV第五章练习p163_5~8
  • 用gdbserver调试共享库(二)
  • java类型通配符
  • 用jQuery实现一些导航条切换,显示隐藏
  • ASP.NET 学习笔记_02 Calender的使用
  • VC++2010开发数字图像系统1
  • 【Amaple教程】5. 插件
  • JavaScript DOM 10 - 滚动
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • Solarized Scheme
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • 阿里云应用高可用服务公测发布
  • 后端_MYSQL
  • 判断客户端类型,Android,iOS,PC
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 我建了一个叫Hello World的项目
  • - 转 Ext2.0 form使用实例
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • #我与Java虚拟机的故事#连载03:面试过的百度,滴滴,快手都问了这些问题
  • ${factoryList }后面有空格不影响
  • (C)一些题4
  • (day6) 319. 灯泡开关
  • (初研) Sentence-embedding fine-tune notebook
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (一)为什么要选择C++
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • (转载)PyTorch代码规范最佳实践和样式指南
  • (轉貼) UML中文FAQ (OO) (UML)
  • .【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)
  • .htaccess 强制https 单独排除某个目录
  • .NET Framework杂记
  • .Net 垃圾回收机制原理(二)
  • .NET 使用配置文件
  • .Net多线程总结
  • .NET构架之我见
  • @converter 只能用mysql吗_python-MySQLConverter对象没有mysql-connector属性’...
  • [ element-ui:table ] 设置table中某些行数据禁止被选中,通过selectable 定义方法解决
  • [ vulhub漏洞复现篇 ] Grafana任意文件读取漏洞CVE-2021-43798
  • [04]Web前端进阶—JS伪数组
  • [cogs2652]秘术「天文密葬法」
  • [HDU] 1054 Strategic Game 入门树形DP
  • [idea]关于idea开发乱码的配置
  • [iOS]让Xcode 4.2生成的app支持老的iOS设备(armv6)
  • [No000016]为什么假期计划总是做不到?