热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android蓝牙源码分析

2019独角兽企业重金招聘Python工程师标准BluetoothService类中定义的Native方法都在android_server_BluetoothServer.c

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 public synchronized boolean enable(IBluetoothDeviceCallback callback) {checkPermissionBluetoothAdmin();Log.d(TAG,"start enable! ");// Airplane mode can prevent Bluetooth radio from being turned on.if (mIsAirplaneSensitive && isAirplaneModeOn()) {return false;}if (mIsEnabled) {return false;}if (mEnableThread != null && mEnableThread.isAlive()) {return false;}// 主要的启动过程是放在一个新起的线程里面,但是不管能不能启动 // 仍然返回了truemEnableThread = new EnableThread(callback);mEnableThread.start();// return true;}private EnableThread mEnableThread;private class EnableThread extends Thread {private final IBluetoothDeviceCallback mEnableCallback;public EnableThread(IBluetoothDeviceCallback callback) {mEnableCallback = callback;}public void run() {boolean res = enableNative();if (res) {mEventLoop.start();}if (mEnableCallback != null) {try {// 通过回调函数来表明是否正常启动蓝牙设备mEnableCallback.onEnableResult(res ?BluetoothDevice.RESULT_SUCCESS :BluetoothDevice.RESULT_FAILURE);} catch (RemoteException e) {}}if (res) {mIsEnabled = true;mIsDiscovering = false;Intent intent = new Intent(BluetoothIntent.ENABLED_ACTION);mContext.sendBroadcast(intent);}}else{mIsEnabled = false;mIsDiscovering = false;}mEnableThread = null;}}// 这个回调函数将被作为参数传进bluetoothservice 里面的enable(IBluetoothDeviceCallback callback)static class DeviceCallback extends IBluetoothDeviceCallback.Stub {Handler messageHandler;public void setHandler(Handler handler) {synchronized (this) {messageHandler = handler;}public void onEnableResult(int result) {switch(result) {// 启动不成功的时候执行case BluetoothDevice.RESULT_FAILURE:messageHandler.sendMessage(messageHandler.obtainMessage(EVENT_FAILED_BT_ENABLE,0));break;}}// 配对完成时执行public void onCreateBondingResult(String address, int result) {synchronized (this) {if (messageHandler != null) {if (result == BluetoothDevice.RESULT_FAILURE) {messageHandler.sendMessage(messageHandler.obtainMessage(HANDLE_PAIRING_FAILED, address));} else {messageHandler.sendMessage(messageHandler.obtainMessage(HANDLE_PAIRING_PASSED, address));}}}}}

涉及到的类: 

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 具体实现文件传输的类

 

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/587974/blog/75162



推荐阅读
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文介绍了在使用Python中的aiohttp模块模拟服务器时出现的连接失败问题,并提供了相应的解决方法。文章中详细说明了出错的代码以及相关的软件版本和环境信息,同时也提到了相关的警告信息和函数的替代方案。通过阅读本文,读者可以了解到如何解决Python连接服务器失败的问题,并对aiohttp模块有更深入的了解。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
author-avatar
爱你想你疼你吻你_514
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有