Android Bluetooth开发

原文地址:http://developer.android.com/guide/topics/wireless/bluetooth.htmlhtml

翻译:jykenanjava

更新:2012.06.19android

Android平台支持蓝牙网络协议栈,实现蓝牙设备之间数据的无线传输。本文档描述了怎样利用android平台提供的蓝牙API去实现蓝压设备之间的通讯。蓝牙具备point-to-point 和 multipoint两种链接功能。
使用蓝牙API,能够作到:
* 搜索蓝牙设备
* 从本地的Bluetooth adapter中查询已经配对的设备
* 创建RFCOMM通道
* 经过service discovery链接到其它设备
* 在设备之间传输数据
* 管理多个链接数据库

基础知识

本文档介绍了如何使用Android的蓝牙API来完成的四个必要的主要任务,使用蓝牙进行设备通讯,主要包含四个部分:蓝牙设置、搜索设备(配对的或可见的)、链接、传输数据。
全部的蓝牙API在android.bluetooth包中。实现这些功能主要须要下面这几个类和接口:安全

BluetoothAdapter
表明本地蓝牙适配器(蓝牙发射器),是全部蓝牙交互的入口。经过它能够搜索其它蓝牙设备,查询已经配对的设备列表,经过已知的MAC地址建立BluetoothDevice,建立BluetoothServerSocket监听来自其它设备的通讯。服务器

BluetoothDevice
表明了一个远端的蓝牙设备, 使用它请求远端蓝牙设备链接或者获取 远端蓝牙设备的名称、地址、种类和绑定状态。 (其信息是封装在 bluetoothsocket 中) 。网络

BluetoothSocket
表明了一个蓝牙套接字的接口(相似于 tcp 中的套接字) ,他是应用程 序经过输入、输出流与其余蓝牙设备通讯的链接点。app

BluetoothServerSocket
表明打开服务链接来监听可能到来的链接请求 (属于 server 端) , 为了链接两个蓝牙设备必须有一个设备做为服务器打开一个服务套接字。 当远端设备发起连 接链接请求的时候,而且已经链接到了的时候,Blueboothserversocket 类将会返回一个 bluetoothsocket。框架

BluetoothClass
描述了一个设备的特性(profile)或该设备上的蓝牙大体能够提供哪些服务(service),但不可信。好比,设备是一个电话、计算机或手持设备;设备能够提供audio/telephony服务等。能够用它来进行一些UI上的提示。
BluetoothProfileless

BluetoothHeadset
提供手机使用蓝牙耳机的支持。这既包括蓝牙耳机和免提(V1.5)模式。

BluetoothA2dp
定义高品质的音频,能够从一个设备传输到另外一个蓝牙链接。 “A2DP的”表明高级音频分配模式。

BluetoothHealth
表明了医疗设备配置代理控制的蓝牙服务

BluetoothHealthCallback
一个抽象类,使用实现BluetoothHealth回调。你必须扩展这个类并实现回调方法接收更新应用程序的注册状态和蓝牙通道状态的变化。

BluetoothHealthAppConfiguration
表明一个应用程序的配置,蓝牙医疗第三方应用注册与远程蓝牙医疗设备交流。

BluetoothProfile.ServiceListener
当他们已经链接到或从服务断开时通知BluetoothProfile IPX的客户时一个接口(即运行一个特定的配置文件,内部服务)。

蓝牙权限

为了在你的应用中使用蓝牙功能,至少要在AndroidManifest.xml中声明两个权限:BLUETOOTH(任何蓝牙相关API都要使用这个权限) 和 BLUETOOTH_ADMIN(设备搜索、蓝牙设置等)。

为了执行蓝牙通讯,例如链接请求,接收链接和传送数据都必须有BLUETOOTH权限。

必需要求BLUETOOTH_ADMIN的权限来启动设备发现或操纵蓝牙设置。大多数应用程序都须要这个权限能力,发现当地的蓝牙设备。此权限授予其余的能力不该该使用,除非应用程序是一个“电源管理”,将根据用户要求修改的蓝牙设置

注释:要请求BLUETOOTH_ADMIN的话,必需要先有BLUETOOTH。

在你的应用manifest 文件中声明蓝牙权限。例如:

1
2
3
4
<manifest ... > <uses-permission android:name="android.permission.BLUETOOTH" /> ... </manifest> 

经过查看<uses-permission>资料来声明应用权限获取更多的信息。

蓝牙设置

在你的应用经过蓝牙进行通讯以前,你须要确认设备是否支持蓝牙,若是支持,确信它被打开。

若是不支持,则不能使用蓝牙功能。若是支持蓝牙,但不可以使用,你刚要在你的应用中请求使用蓝牙。这个要两步完成,使用BluetoothAdapter。

1.获取BluetoothAdapter

全部的蓝牙活动请求BluetoothAdapter,为了获取BluetoothAdapter,呼叫静态方法getDefaultAdapter() 。这个会返回一个BluetoothAdapter,表明设备本身的蓝牙适配器(蓝牙无线电)。这个蓝牙适配器应用于整个系统中,你的应用能够经过这个对象进行交互。若是getDefaultAdapter()返回null,则这个设备不支持蓝牙。例如:

1
2
3
4
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { // Device does not support Bluetooth } 

2.打开蓝牙

其次。你须要肯定蓝牙可以使用。经过isEnabled()来检查蓝牙当前是否可用。若是这个方法返回false,则蓝牙不可以使用。为了请求蓝牙使用,呼叫startActivityForResult()与的ACTION_REQUEST_ENABLE动做意图。经过系统设置中启用蓝牙将发出一个请求(不中止蓝牙应用)。例如:

1
2
3
4
if (!mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } 

![http://developer.android.com/images/bt_enable_request.png]

对话框中显示请求使用蓝牙权限。若是响应"Yes",这个进程完成(或失败)后你的应用将可以使用蓝牙。
REQUEST_ENABLE_BT常量做为一个整型传到startActivityForResult()中(值必须大于0),该系统传回给你,在你onActivityResult()做为实现的requestCode参数。

若是调用蓝牙成功,你的Activity就会在onActivityResult()中收到RESULT_OK结果,若是蓝牙不能使用因为错误(或用户响应“NO”那么结果返回RESULT_CANCELED。

除了经过onActivityResult(),还能够经过监听ACTION_STATE_CHANGED这个broadcast Intent来知道蓝牙状态是否改变。这个Intent包含EXTRA_STATE,EXTRA_PREVIOUS_STATE两个字段,分别表明新旧状态。可能的值是STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, 还有STATE_OFF。

小贴: Enabling discoverability 将自动启用蓝牙。若是您计划执行蓝牙活动以前,始终使设备可发现,你能够跳过上面的步骤2。参阅enabling discoverability。

搜索设备

使用BluetoothAdapter能够经过设备搜索或查询配对设备找到远程Bluetooth设备。

Device discovery(设备搜索)是一个扫描搜索本地已使能Bluetooth设备而且从搜索到的设备请求一些信息的过程(有时候会收到相似“discovering”,“inquiring”或“scanning”)。可是,搜索到的本地Bluetooth设备只有在打开被发现功能后才会响应一个discovery请求,响应的信息包括设备名,类,惟一的MAC地址。发起搜寻的设备可使用这些信息来初始化跟被发现的设备的链接。
一旦与远程设备的第一次链接被创建,一个pairing请求就会自动提交给用户。若是设备已配对,配对设备的基本信息(名称,类,MAC地址)就被保存下来了,可以使用Bluetooth API来读取这些信息。使用已知的远程设备的MAC地址,链接能够在任什么时候候初始化而没必要先完成搜索(固然这是假设远程设备是在可链接的空间范围内)。

须要记住,配对和链接是两个不一样的概念:

配对意思是两个设备相互意识到对方的存在,共享一个用来鉴别身份的链路键(link-key),可以与对方创建一个加密的链接。

链接意思是两个设备如今共享一个RFCOMM信道,可以相互传输数据。

目前Android Bluetooth API's要求设备在创建RFCOMM信道前必须配对(配对是在使用Bluetooth API初始化一个加密链接时自动完成的)。

下面描述如何查询已配对设备,搜索新设备。

注意:Android的电源设备默认是不能被发现的。用户能够经过系统设置让它在有限的时间内能够被发现,或者能够在应用程序中要求用户使能被发现功能。

查找匹配设备

在搜索设备前,查询配对设备看须要的设备是否已是已经存在是很值得的,能够调用getBondedDevices()来作到,该函数会返回一个描述配对设备BluetoothDevice的结果集。例如,可使用ArrayAdapter查询全部配对设备而后显示全部设备名给用户:

1
2
3
4
5
6
7
8
9
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); // If there are paired devices if (pairedDevices.size() > 0) { // Loop through paired devices for (BluetoothDevice device : pairedDevices) { // Add the name and address to an array adapter to show in a ListView mArrayAdapter.add(device.getName() + "n" + device.getAddress()); } }; 

BluetoothDevice对象中须要用来初始化一个链接惟一须要用到的信息就是MAC地址。

扫描设备

要开始搜索设备,只需简单的调用startDiscovery() 。该函数时异步的,调用后当即返回,返回值表示搜索是否成功开始。搜索处理一般包括一个12秒钟的查询扫描,而后跟随一个页面显示搜索到设备Bluetooth名称。

应用中能够注册一个带ACTION_FOUND Intent的BroadcastReceiver,搜索到每个设备时都接收到消息。对于每个设备,系统都会广播ACTION_FOUND Intent,该Intent携带着而外的字段信息EXTRA_DEVICEEXTRA_CLASS,分别包含一个BluetoothDevice和一个BluetoothClass。

下面的示例显示如何注册和处理设备被发现后发出的广播:

代码以下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
   // Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // When discovery finds a device if (BluetoothDevice.ACTION_FOUND.equals(action)) { // Get the BluetoothDevice object from the Intent BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // Add the name and address to an array adapter to show in a ListView mArrayAdapter.add(device.getName() + "n" + device.getAddress()); } } }; // Register the BroadcastReceiver IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy 

警告:完成设备搜索对于Bluetooth适配器来讲是一个重量级的处理,要消耗大量它的资源。一旦你已经找到一个设备来链接,请确保你在尝试链接前使用了cancelDiscovery()来中止搜索。一样,若是已经保持了一个链接的时候,同时执行搜索设备将会显著的下降链接的带宽,因此在链接的时候不该该执行搜索发现。

使能被发现

若是想让本地设备被其余设备发现,能够带ACTION_REQUEST_DISCOVERABLE action Intent调用startActivityForResult(Intent, int) 方法。该方法会提交一个请求经过系统刚设置使设备出于能够被发现的模式(而不影响应用程序)。默认状况下,设备在120秒后变为能够被发现的。能够经过额外增长EXTRA_DISCOVERABLE_DURATION Intent自定义一个值,最大值是3600秒,0表示设备老是能够被发现的(小于0或者大于3600则会被自动设置为120秒)。下面示例设置时间为300:

1
2
3
4
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(discoverableIntent); 

!
[http://developer.android.com/images/bt_enable_discoverable.png]

询问用户是否容许打开设备能够被发现功能时会显示一个对话框。若是用户选择“Yes”,设备会在指定时间事后变为能够被发现的。Activity的onActivityResult()回调函数被调用,结果码等于设备变为能够被发现所需时长。若是用户选择“No”或者有错误发生,结果码会是Activity.RESULT_CANCELLED。

提示:若是Bluetooth没有启用,启用Bluetooth可被发现功能可以自动开启Bluetooth。

在规定的时间内,设备会静静的保持能够被发现模式。若是想在能够被发现模式被更改时受到通知,能够用ACTION_SCAN_MODE_CHANGED Intent注册一个BroadcastReceiver,包含额外的字段信息EXTRA_SCAN_MODE和EXTRA_PREVIOUS_SCAN_MODE分别表示新旧扫描模式,其可能的值为SCAN_MODE_CONNECTABLE_DISCOVERABLE(discoverable mode),SCAN_MODE_CONNECTABLE(not in discoverable mode but still able to receive connections),SCAN_MODE_NONE(not in discoverable mode and unable to receive connections)。
若是只须要链接远程设备就不须要打开设备的能够被发现功能。只在应用做为一个服务器socket的宿主用来接收进来的链接时才须要使能能够被发现功能,由于远程设备在初始化链接前必须先发现了你的设备。

链接设备

为了在两台设备上建立一个链接,你必须在软件上实现服务器端和客户端的机制,由于一个设备必须必须打开一个server socket,而另外一个必须初始化这个链接(使用服务器端设备的MAC地址进行初始化)。
当服务器端和客户端在同一个RFCOMM信道上都有一个BluetoothSocket时,就能够认为它们之间创建了一个链接。在这个时刻,每一个设备能得到一个输出流和一个输入流,也可以开始数据传输。本节介绍如何在两个设备之间初始化一个链接。
服务器端和客户端得到BluetoothSocket的方法是不一样的,服务器端是当一个进入的链接被接受时才产生一个BluetoothSocket,客户端是在打开一个到服务器端的RFCOMM信道时得到BluetoothSocket的。

!
[http://developer.android.com/images/bt_pairing_request.png]

一种实现技术是,每个设备都自动做为一个服务器,因此每一个设备都有一个server socket并监听链接。而后每一个设备都能做为客户端创建一个到另外一台设备的链接。另一种代替方法是,一个设备按需打开一个server socket,另一个设备仅初始化一个到这个设备的链接。

Note: 若是两个设备在创建链接以前并无配对,那么在创建链接的过程当中,Android框架将自动显示一个配对请求的notification或者一个对话框,如Figure 3所示。因此,在尝试链接设备时,你的应用程序无需确保设备之间已经进行了配对。你的RFCOMM链接将会在用户确认配对以后继续进行,或者用户拒绝或者超时以后失败。

做为服务器链接

若是要链接两个设备,其中一个必须充当服务器,经过持有一个打开的BluetoothServerSocket对象。服务器socket的做用是侦听进来的链接,若是一个链接被接受,提供一个链接好的BluetoothSocket对象。从BluetoothServerSocket获取到BluetoothSocket对象以后,BluetoothServerSocket就能够(也应该)丢弃了,除非你还要用它来接收更多的链接。

下面是创建服务器socket和接收一个链接的基本步骤:

1.经过调用listenUsingRfcommWithServiceRecord(String, UUID)获得一个BluetoothServerSocket对象。

该字符串为服务的识别名称,系统将自动写入到一个新的服务发现协议(SDP)数据库接入口到设备上的(名字是任意的,能够简单地是应用程序的名称)项。 UUID也包括在SDP接入口中,将是客户端设备链接协议的基础。也就是说,当客户端试图链接本设备,它将携带一个UUID用来惟一标识它要链接的服务,UUID必须匹配,链接才会被接受。

2.经过调用accept()来侦听链接请求。

这是一个阻塞的调用,知道有链接进来或者产生异常才会返回。只有远程设备发送一个链接请求,而且携带的UUID与侦听它socket注册的UUID匹配,链接请求才会被接受。若是成功,accept()将返回一个链接好的BluetoothSocket对象。

3.除非须要再接收另外的链接,不然的话调用close() 。

close()释放server socket和它的资源,但不会关闭链接accept()返回的链接好的BluetoothSocket对象。与TCP/IP不一样,RFCOMM同一时刻一个信道只容许一个客户端链接,所以大多数状况下意味着在BluetoothServerSocket接受一个链接请求后应该当即调用close()。

accept()调用不该该在主Activity UI线程中进行,由于这是个阻塞的调用,会妨碍其余的交互。常常是在在一个新线程中作BluetoothServerSocket或BluetoothSocket的全部工做来避免UI线程阻塞。注意全部BluetoothServerSocket或BluetoothSocket的方法都是线程安全的。

示例:

下面是一个简单的接受链接的服务器组件代码示例:

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; public AcceptThread() { // Use a temporary object that is later assigned to mmServerSocket, // because mmServerSocket is final BluetoothServerSocket tmp = null; try { // MY_UUID is the app's UUID string, also used by the client code tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); } catch (IOException e) { } mmServerSocket = tmp; } public void run() { BluetoothSocket socket = null; // Keep listening until exception occurs or a socket is returned while (true) { try { socket = mmServerSocket.accept(); } catch (IOException e) { break; } // If a connection was accepted if (socket != null) { // Do work to manage the connection (in a separate thread) manageConnectedSocket(socket); mmServerSocket.close(); break; } } } /* * Will cancel the listening socket, and cause the thread to finish * / public void cancel() { try { mmServerSocket.close(); } catch (IOException e) { } } } 

本例中,仅仅只接受一个进来的链接,一旦链接被接受获取到BluetoothSocket,就发送获取到的BluetoothSocket给一个单独的线程,而后关闭BluetoothServerSocket并跳出循环。

注意:accept()返回BluetoothSocket后,socket已经链接了,因此在客户端不该该呼叫connnect()。

manageConnectedSocket()是一个虚方法,用来初始化线程好传输数据。

一般应该在处理完侦听到的链接后当即关闭BluetoothServerSocket。在本例中,close()在获得BluetoothSocket后立刻被调用。还须要在线程中提供一个公共的方法来关闭私有的BluetoothSocket,中止服务端socket的侦听。

做为客户端链接

为了实现与远程设备的链接,你必须首先得到一个表明远程设备BluetoothDevice对象。而后使用BluetoothDevice对象来获取一个BluetoothSocket来实现来接。

下面是基本的步骤:

1.用BluetoothDevice调用createRfcommSocketToServiceRecord(UUID)获取一个BluetoothSocket对象。
这个初始化的BluetoothSocket会链接到BluetoothDevice。UUID必须匹配服务器设备在打开BluetoothServerSocket 时用到的UUID(用java.util.UUID) listenUsingRfcommWithServiceRecord(String, UUID)。能够简单的生成一个UUID串而后在服务器和客户端都使用该UUID。

2.调用connect()完成链接
当调用这个方法的时候,系统会在远程设备上完成一个SDP查找来匹配UUID。若是查找成功而且远程设备接受链接,就共享RFCOMM信道,connect()会返回。这也是一个阻塞的调用,无论链接失败仍是超时(12秒)都会抛出异常。

注意:要确保在调用connect()时没有同时作设备查找,若是在查找设备,该链接尝试会显著的变慢,慢得相似失败了。

实例:
下面是一个完成Bluetooth链接的样例线程:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; public ConnectThread(BluetoothDevice device) { // Use a temporary object that is later assigned to mmSocket, // because mmSocket is final BluetoothSocket tmp = null; mmDevice = device; // Get a BluetoothSocket to connect with the given BluetoothDevice try { // MY_UUID is the app's UUID string, also used by the server code tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { } mmSocket = tmp; } public void run() { // Cancel discovery because it will slow down the connection mBluetoothAdapter.cancelDiscovery(); try { // Connect the device through the socket. This will block // until it succeeds or throws an exception mmSocket.connect(); } catch (IOException connectException) { // Unable to connect; close the socket and get out try { mmSocket.close(); } catch (IOException closeException) { } return; } // Do work to manage the connection (in a separate thread) manageConnectedSocket(mmSocket); } /* * Will cancel an in-progress connection, and close the socket * / public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } } 

注意 : 到cancelDiscovery()在链接操做前被调用。在链接以前,无论搜索有没有进行,该调用都是安全的,不须要确认(固然若是有要确认的需求,能够调用isDiscovering() )。
manageConnectedSocket()是一个虚方法,用来初始化线程好传输数据。
在对BluetoothSocket的处理完成后,记得调用close()来关闭链接的socket和清理全部的内部资源。

管理链接

若是已经链接了两个设备,他们都已经拥有各自的链接好的BluetoothSocket对象。那就是一个有趣的开始,由于你能够在设备间共享数据了。使用BluetoothSocket,传输任何数据一般来讲都很容易了:

1.经过socket获取输入输出流来处理传输(分别使用getInputStream()getOutputStream() )。

2.用read(byte[])和write(byte[])来实现读写。

仅此而已。

固然,仍是有不少细节须要考虑的。首要的,须要用一个专门的线程来实现流的读写。只是很重要的,由于read(byte[])和write(byte[])都是阻塞的调用。read(byte[])会阻塞直到流中有数据可读。write(byte[])一般不会阻塞,可是若是远程设备调用read(byte[])不够快致使中间缓冲区满,它也可能阻塞。因此线程中的主循环应该用于读取InputStream。线程中也应该有单独的方法用来完成写OutputStream

示例

下面是一个如上面描述那样的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket) { mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // Get the input and output streams, using temp objects because // member streams are final try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { byte[] buffer = new byte[1024]; // buffer store for the stream int bytes; // bytes returned from read() // Keep listening to the InputStream until an exception occurs while (true) { try { // Read from the InputStream bytes = mmInStream.read(buffer); // Send the obtained bytes to the UI activity mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer) .sendToTarget(); } catch (IOException e) { break; } } } /* Call this from the main activity to send data to the remote device * / public void write(byte[] bytes) { try { mmOutStream.write(bytes); } catch (IOException e) { } } /* Call this from the main activity to shutdown the connection * / public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } } 

构造函数中获得须要的流,一旦执行,线程会等待从InputStream来的数据。当read(byte[])返回从流中读到的字节后,数据经过父类的成员Handler被送到主Activity,而后继续等待读取流中的数据。
向外发送数据只需简单的调用线程的write()方法。
线程的cancel()方法时很重要的,以便链接能够在任什么时候候经过关闭BluetoothSocket来终止。它应该总在处理完Bluetooth链接后被调用。

使用配置文件

从Android 3.0开始,Bluetooth API就包含了对Bluetooth profiles的支持。 Bluetooth profile是基于蓝牙的设备之间通讯的无线接口规范。 例如Hands-Free profile(免提模式)。 若是移动电话要链接一个无线耳机,他们都要支持Hands-Free profile。

你在你的类里能够完成BluetoothProfile接口来支持某一Bluetooth profiles。Android Bluetooth API完成了下面的Bluetooth profile:

  • 耳机。 Headset profile提供了移动电话上的Bluetooth耳机支持。Android提供了BluetoothHeadset类,它是一个协议,用来经过IPC(interprocess communication)控制Bluetooth Headset Service。BluetoothHeadset既包含Bluetooth Headset profile也包含Hands-Free profile,还包括对AT命令的支持。
  • A2DP. Advanced Audio Distribution Profile (A2DP) profile,高级音频传输模式。Android提供了BluetoothA2dp类,这是一个经过IPC来控制Bluetooth A2DP的协议。
  • Android4.0(API级别14)推出了支持蓝牙医疗设备模式(HDP),这使您能够建立支持蓝牙的医疗设备,使用蓝牙通讯的应用程序,例如心率监视器,血液,温度计和秤等等。 支持的设备和相应的设备数据专业化代码,请参阅蓝牙分配在www.bluetooth.org数。请注意,这些值的ISO / IEEE11073-20601引用[7] MDC_DEV_SPEC_PROFILE_* 命名代码附件的规范。 对于更多的HDP讨论, 查看Health Device Profile.

下面是使用profile的基本步骤:

1.获取默认的Bluetooth适配器。

2.使用getProfileProxy()来创建一个与profile相关的profile协议对象的链接。在下面的例子中,profile协议对象是BluetoothHeadset的一个实例。

3.设置BluetoothProfile.ServiceListener。该listener通知BluetoothProfile IPC客户端,当客户端链接或断连服务器的时候

4.在[android.bluetooth.BluetoothProfile) onServiceConnected()](http://docs.eoeandroid.com/reference/android/bluetooth/BluetoothProfile.ServiceListener.html#onServiceConnectedint,)内,获得一个profile协议对象的句柄。(

5.一旦拥有了profile协议对象,就能够用它来监控链接的状态,完成于该profile相关的其余操做。

例如,下面的代码片断显示如何链接到一个BluetoothHeadset协议对象,用来控制Headset profile:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
BluetoothHeadset mBluetoothHeadset; // Get the default adapter BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // Establish connection to the proxy. mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET); private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() { public void onServiceConnected(int profile, BluetoothProfile proxy) { if (profile == BluetoothProfile.HEADSET) { mBluetoothHeadset = (BluetoothHeadset) proxy; } } public void onServiceDisconnected(int profile) { if (profile == BluetoothProfile.HEADSET) { mBluetoothHeadset = null; } } }; // ... call functions on mBluetoothHeadset // Close proxy connection after use. mBluetoothAdapter.closeProfileProxy(mBluetoothHeadset) 

Vendor-specific AT 指令

从Android 3.0开始,应用程序能够注册侦听预约义的Vendor-specific AT命令这样的系统广播(如Plantronics +XEVENT command)。例如,应用能够接收到一个广播,该广播代表链接的设备电量太低,而后通知用户作好其余须要的操做。建立一个带ACTION_VENDOR_SPECIFIC_HEADSET_EVENT intent的broadcast receiver来为耳机处理

医疗设备模式

Android4.0(API级别14)推出了支持蓝牙医疗设备模式(HDP),这使您能够建立支持蓝牙的医疗设备,使用蓝牙通讯的应用程序,例如心率监视器,血液,温度计和秤。蓝牙卫生API包括基础类BluetoothHealthBluetoothHealthCallbackBluetoothHealthAppConfiguration
在使用蓝牙卫生API,它有助于理解这些关键的HDP概念:

QQ截图20130314152342.png

建立一个 HDP 应用

建立 一个Android HDP应用要下面几步:

1.获取一个参考的BluetoothHealth代理对象.

相似普通的耳机和A2DP设备,你必须调用BluetoothProfile与getProfileProxy() 。ServiceListener 和医疗配置类型来创建一个配置代理对象的链接。

2.建立一个BluetoothHealthCallback和注册的应用程序配置(BluetoothHealthAppConfiguration)做为一个医疗sink。

3.创建一个链接到医疗设备。一些设备将初始化链接。 开展这一步对于这些设备,这是没必要要的。

4.当链接成功到一个医疗设备时,使用文件描述符读/写到医疗设备。

接收到的数据须要使用健康管理,实现了IEEE11073-XXXXX规范进行解释。

5.当完成后,关闭医疗通道和注销申请。通道也有延伸静止时关闭。

为了完善这个例子说明这些步骤。查看Bluetooth HDP (Health Device Profile) 。

相关文章
相关标签/搜索