2024年6月3日发(作者:)

Android蓝牙开发

学习之前先了解两个基本概念:

协议:

一个基于欧洲电信标准协会ETSI07.10规程的串行线性仿真协议。此协议提供RS232控

制和状态信号,如基带上的损坏,CTS以及数据信号等,为上层业务(如传统的串行线缆应

用)提供了传送能力。

RFCOMM是一个简单传输协议,其目的是针对如何在两个不同设备上的应用之间保证

一条完整的通信路径,并在它们之间保持一通信段。

RFCOMM是为了兼容传统的串口应用,同时取代有线的通信方式,蓝牙协议栈需要提

供与有线串口一致的通信接口而开发出的协议。RFCOMM协议提供对基于L2CAP协议的串

口仿真,基于ETSI07.10。可支持在两个BT设备之间同时保持高达60路的通信连接。

RFCOMM只针对直接互连设备之间的连接,或者是设备与网络接入设备之间的互连。

通信两端设备必须兼容于RFCOMM协议,有两类设备:DTE (Data Terminal Endpoint,通信

终端,如PC,PRINTER)和DCE (Data Circuit Endpoint,通信段的一部分,如Modem)。此两

类设备不作区分。

硬件地址

MAC(Medium/MediaAccess Control, 介质访问控制)MAC地址是烧录在

NetworkInterfaceCard(网卡,NIC)里的.MAC地址,也叫硬件地址,是由48比特长(6字节),16进制

的数字组成.0-23位叫做组织唯一标志符(organizationally unique,是识别LAN(局域网)节点的

标识.24-47位是由厂家自己分配。其中第40位是组播地址标志位。网卡的物理地址通常是由

网卡生产厂家烧入网卡的EPROM(一种闪存芯片,通常可以通过程序擦写),它存储的是传

输数据时真正赖以标识发出数据的电脑和接收数据的主机的地址。

Android平台提供的蓝牙API去实现蓝牙设备之间的通信,蓝牙设备之间的通信主要包括

了四个步骤:设置蓝牙设备、寻找局域网内可能或者匹配的设备、连接设备和设备之间的数

据传输。以下是建立蓝牙连接的所需要的一些基本类:

BluetoothAdapter类:代表了一个本地的蓝牙适配器。它是所有蓝牙交互的的入口点。

利用它你可以发现其他蓝牙设备,查询绑定了的设备,使用已知的MAC地址实例化一个蓝

牙设备和建立一个BluetoothServerSocket(作为服务器端)来监听来自其他设备的连接。

BluetoothDevice类:代表了一个远端的蓝牙设备,使用它请求远端蓝牙设备连接或者获

取远端蓝牙设备的名称、地址、种类和绑定状态(其信息是封装在BluetoothSocket中)。

BluetoothSocket类:代表了一个蓝牙套接字的接口(类似于TCP中的套接字),它是应

用程序通过输入、输出流与其他蓝牙设备通信的连接点。

BlueboothServerSocket类:代表打开服务连接来监听可能到来的连接请求(属于server

端),为了连接两个蓝牙设备必须有一个设备作为服务器打开一个服务套接字。当远端设备

发起连接连接请求的时候,并且已经连接到了的时候,BlueboothServerSocket类将会返回一

个BluetoothSocket。

BluetoothClass类:描述了一个蓝牙设备的一般特点和能力。它的只读属性集定义了设

备的主、次设备类和一些相关服务。然而,它并没有准确地描述所有该设备所支持的蓝牙文

件和服务,而是作为对设备种类来说的一个小小暗示。

要操作蓝牙,先要在里加入权限:

Android所有关于蓝牙开发的类都在oth包下,只有8个类。常用的四

个类如下所示:

1. BluetoothAdapter

蓝牙适配器,直到我们建立BluetoothSocket连接之前,都要不断操作它。

BluetoothAdapter里的方法很多,常用的有以下几个:

cancelDiscovery()取消发现,也就是说当我们正在搜索设备的时候调用这个方法将不

再继续搜索

disable()关闭蓝牙

enable()打开蓝牙,这个方法打开蓝牙不会弹出提示,更多的时候我们需要问下用户是

否打开,以下两行代码同样是打开蓝牙,但会提示用户:

Intentenabler = new Intent(_REQUEST_ENABLE);

startActivityForResult(enabler,reCode); //同startActivity(enabler);

getAddress()获取本地蓝牙地址

getDefaultAdapter()获取默认BluetoothAdapter,实际上,也只有这一种方法获取

BluetoothAdapter

getName()获取本地蓝牙名称

getRemoteDevice(String address)根据蓝牙地址获取远程蓝牙设备

getState()获取本地蓝牙适配器当前状态(感觉可能调试的时候更需要)

isDiscovering()判断当前是否正在查找设备,是则返回true

isEnabled()判断蓝牙是否打开,已打开返回true,否则返回false

listenUsingRfcommWithServiceRecord(String name,UUID uuid)根据名称,UUID创建

并返回BluetoothServerSocket,这是创建BluetoothSocket服务器端的第一步

startDiscovery()开始搜索,这是搜索的第一步

2. BluetoothDevice

描述了一个蓝牙设备

createRfcommSocketToServiceRecord(UUIDuuid)根据UUID创建并返回一个

BluetoothSocket,这个方法也是我们获取BluetoothDevice的目的——创建

BluetoothSocket

这个类其他的方法,如getAddress()、getName()等,同BluetoothAdapter。

3. BluetoothServerSocket

如果去除了Bluetooth相信大家一定再熟悉不过了,既然是Socket,方法就应该都差不

多,这个类一种只有三个方法:

两个重载的accept(),accept(int timeout)

两者的区别在于后面的方法指定了过时时间,需要注意的是,执行这两个方法的时候,

直到接收到了客户端的请求(或是过期之后),都会阻塞线程,应该放在新线程里运行。还

有一点需要注意的是,这两个方法都返回一个BluetoothSocket,最后的连接也是服务器端

与客户端的两个BluetoothSocket的连接

close()关闭

4. BluetoothSocket是客户端,跟BluetoothServerSocket相对

一共5个方法,不出意外,都会用到

close()关闭

connect()连接

getInptuStream()获取输入流

getOutputStream()获取输出流

getRemoteDevice()获取远程设备

这里指的是获取bluetoothSocket指定连接的那个远程蓝牙设备

下面说说具体的编程实现

1.启动蓝牙功能:

首先通过调用静态方法getDefaultAdapter()获取蓝牙适配器BluetoothAdapter,以后你就

可以使用该对象了。如果返回为空,则无法继续执行了。例如:

BluetoothAdapter mBluetoothAdapter = aultAdapter();

if (mBluetoothAdapter == null) {

// Device does not support Bluetooth

}

其次,调用isEnabled()来查询当前蓝牙设备的状态,如果返回为false,则表示蓝牙设备

没有开启,接下来你需要封装一个ACTION_REQUEST_ENABLE请求到intent里面,调用

startActivityForResult()方法使能蓝牙设备,例如:

if (!led()) {

Intent enableBtIntent = new Intent(_REQUEST_ENABLE);

startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

}

2. 查找设备:

使用BluetoothAdapter类里的方法,你可以查找远端设备(大概十米以内)或者查询在

你手机上已经匹配(或者说绑定)的其他手机了。当然需要确定对方蓝牙设备已经开启或者

已经开启了“被发现使能”功能(对方设备是可以被发现的是你能够发起连接的前提条件)。

如果该设备是可以被发现的,会反馈回来一些对方的设备信息,比如名字、MAC地址等,

利用这些信息,你的设备就可以选择去向对方初始化一个连接。

如果你是第一次与该设备连接,那么一个配对的请求就会自动的显示给用户。当设备配

对好之后,他的一些基本信息(主要是名字和MAC)被保存下来并可以使用蓝牙的API来读

取。使用已知的MAC地址就可以对远端的蓝牙设备发起连接请求。

匹配好的设备和连接上的设备的不同点:匹配好只是说明对方设备发现了你的存在,并

拥有一个共同的识别码,并且可以连接。连接上:表示当前设备共享一个RFCOMM信道并

且两者之间可以交换数据。也就是是说蓝牙设备在建立RFCOMM信道之前,必须是已经配

对好了的。

3. 查询匹配好的设备:

在建立连接之前你必须先查询配对好了的蓝牙设备集(你周围的蓝牙设备可能不止一

个),以便你选取哪一个设备进行通信,例如你可以你可以查询所有配对的蓝牙设备,并使

用一个数组适配器将其打印显示出来:

Set pairedDevices = dedDevices();

// If there are paired devices

if (() > 0) {

//Loop through paired devices

for (BluetoothDevice device : pairedDevices) {

// Add the name and address to an array adapter to show in a ListView

(e() + "n" + ress());

}

建立一个蓝牙连接只需要MAC地址就已经足够了。

4.

扫描设备:

扫描设备,只需要简单的调用startDiscovery()方法,这个扫描的过程大概持续是12秒,应用

程序为了ACTION_FOUND动作需要注册一个BroadcastReceiver来接受设备扫描到的信息。

对于每一个设备,系统都会广播ACTION_FOUND动作。例如:

// Create a BroadcastReceiver for ACTION_FOUND

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

public void onReceive(Context context, Intent intent) {

String action = ion();

// When discovery finds a device

if (_(action)) {

// Get the BluetoothDevice object from the Intent

BluetoothDevice device =

celableExtra(_DEVICE);

// Add the name and address to an array adapter to show in a ListView

(e() + "n" + ress());

}

}

};

// Register the BroadcastReceiver

IntentFilter filter = new IntentFilter(_FOUND);

registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy

注意:扫描的过程是一个很耗费资源的过程,一旦你找到你需要的设备之后,在发起连接请

求之前,确保你的程序调用cancelDiscovery()方法停止扫描。显然,如果你已经连接上一个

设备,启动扫描会减少你的通信带宽。

5. 使能被发现:Enabling discoverability

如果你想使你的设备能够被其他设备发现,将ACTION_REQUEST_DISCOVERABLE动

作封装在intent中并调用startActivityForResult(Intent, int)方法就可以了。它将在不使你应用程

序退出的情况下使你的设备能够被发现。缺省情况下的使能时间是120秒,当然你可以可以

通过添加EXTRA_DISCOVERABLE_DURATION字段来改变使能时间(最大不超过300秒,

这是出于对你设备上的信息安全考虑)。例如:

Intent discoverableIntent = new

Intent(_REQUEST_DISCOVERABLE);

ra(_DISCOVERABLE_DURATION, 300);

startActivity(discoverableIntent);

运行该段代码之后,系统会弹出一个对话框来提示你启动设备使能被发现(此过程中如

果你的蓝牙功能没有开启,系统会帮你开启),并且如果你准备对该远端设备发现一个连接,

你不需要开启使能设备被发现功能,因为该功能只是在你的应用程序作为服务器端的时候才

需要。

6. 连接设备:

在应用程序中,想建立两个蓝牙设备之间的连接,必须实现客户端和服务器端的代码(因

为任何一个设备都必须可以作为服务端或者客户端)。一个开启服务来监听,一个发起连接

请求(使用服务器端设备的MAC地址)。当他们都拥有一个蓝牙套接字在同一RFECOMM信

道上的时候,可以认为他们之间已经连接上了。服务端和客户端通过不同的方式或其他们的

蓝牙套接字。当一个连接监听到的时候,服务端获取到蓝牙套接字。当客户可打开一个

FRCOMM信道给服务器端的时候,客户端获取到蓝牙套接字。

注意:在此过程中,如果两个蓝牙设备还没有配对好的,android系统会通过一个通知或

者对话框的形式来通知用户。RFCOMM连接请求会在用户选择之前阻塞。如下图:

7. 服务端的连接:

当你想要连接两台设备时,一个必须作为服务端(通过持有一个打开的

BluetoothServerSocket),目的是监听外来连接请求,当监听到以后提供一个连接上的

BluetoothSocket给客户端,当客户端从BluetoothServerSocket得到BluetoothSocket以后就可以

销毁BluetoothServerSocket,除非你还想监听更多的连接请求。

建立服务套接字和监听连接的基本步骤:

首先通过调用listenUsingRfcommWithServiceRecord(String, UUID)方法来获取

BluetoothServerSocket对象,参数String代表了该服务的名称,UUID代表了和客户端连接的

一个标识(128位格式的字符串ID,相当于PIN码),UUID必须双方匹配才可以建立连接。

其次调用accept()方法来监听可能到来的连接请求,当监听到以后,返回一个连接上的蓝

牙套接字BluetoothSocket。最后,在监听到一个连接以后,需要调用close()方法来关闭监

听程序。(一般蓝牙设备之间是点对点的传输)

注意:accept()方法不应该放在主Acitvity里面,因为它是一种阻塞调用(在没有监听

到连接请求之前程序就一直停在那里)。解决方法是新建一个线程来管理。例如:

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 theclient code

tmp = UsingRfcommWithServiceRecord(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 = ();

} catch (IOException e) {

break;

}

// If a connection was accepted

if (socket != null) {

// Do work to manage the connection (in a separate thread)

manageConnectedSocket(socket);

();

break;

}

}

}

/** Will cancel the listening socket, and cause the thread to finish */

public void cancel() {

try {

();

} catch (IOException e) { }

}

}

8. 客户端的连接:

为了初始化一个与远端设备的连接,需要先获取代表该设备的一个BluetoothDevice对象。

通过BluetoothDevice对象来获取BluetoothSocket并初始化连接,具体步骤:

使用BluetoothDevice对象里的方法createRfcommSocketToServiceRecord(UUID)来获取

BluetoothSocket。UUID就是匹配码。然后,调用connect()方法来。如果远端设备接收了

该连接,他们将在通信过程中共享RFFCOMM信道,并且connect()方法返回。例如:

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 = RfcommSocketToServiceRecord(MY_UUID);

} catch (IOException e) { }

mmSocket = tmp;

}

public void run() {

// Cancel discovery because it will slow down the connection

Discovery();

try {

// Connect the device through the socket. This will block

// until it succeeds or throws an exception

t();

} catch (IOException connectException) {

// Unable to connect; close the socket and get out

try {

();

} catch (IOException closeException) { }

return;

}

// Do work to manage the connection (in a separate thread)

manageConnectedSocket(mmSocket);

}

注意:conncet()方法也是阻塞调用,一般建立一个独立的线程中来调用该方法。在设备

discover过程中不应该发起连接connect(),这样会明显减慢速度以至于连接失败。且数据

传输完成只有调用close()方法来关闭连接,这样可以节省系统内部资源。

9. 管理连接(主要涉及数据的传输):

当设备连接上以后,每个设备都拥有各自的BluetoothSocket。现在你就可以实现设备之

间数据的共享了。

1> 首先通过调用getInputStream()和getOutputStream()方法来获取输入输出流。然后通过

调用read(byte[]) 和write(byte[]).方法来读取或者写数据。

2> 实现细节:以为读取和写操作都是阻塞调用,需要建立一个专用现成来管理。

3>

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 = utStream();

tmpOut = putStream();

} 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 = (buffer);

// Send the obtained bytes to the UI Activity

Message(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 {

(bytes);

} catch (IOException e) { }

}

/* Call this from the main Activity to shutdown the connection */

public void cancel() {

try {

();

} catch (IOException e) { }

}

}

BluetoothChat 例程分析

Google 提供的关于 Bluetooth 开发的例程为 Bluetoothchat。除去配置及 UI定义等文

件,主程序文件共三个: 、 以及

,详细功能可见下面的描述。

例程的主 Activity 。 onCreate() 得到本地 BluetoothAdapter 设备,检查是否支持。

onStart() 中检查是否启用蓝牙,并请求启用,然后执行 setupChat()。 setupChat() 中

先对界面中的控件进行初始化增加点击监听器等,然创建 BluetoothChatService 对象,该

对象在整个应用过程中存在,并执行蓝牙连接建立、消息发送接受等实际的行为。

public synchronized void start() :

开启 mAcceptThread 线程,由于样例程序是仅 2 人的聊天过程,故之前先检测

mConnectThread 和 mConnectedThread 是否运行,运行则先退出这些线程。

public synchronized void connect(BluetoothDevice device) :

取消 CONNECTING 和 CONNECTED 状态下的相关线程,然后运行新的 mConnectThread 线程。

public synchronized void connected(BluetoothSocket socket, BluetoothDevice

device) :

开启一个 ConnectedThread 来管理对应的当前连接。之前先取消任意现存的

mConnectThread 、 mConnectedThread 、 mAcceptThread 线程,然后开启新

mConnectedThread ,传入当前刚刚接受的 socket 连接。最后通过 Handler 来通知 UI

连接 OK 。

public synchronized void stop() :停止所有相关线程,设当前状态为 NONE 。

public void write(byte[] out) :在 STATE_CONNECTED 状态下,调用

mConnectedThread 里的 write 方法,写入 byte 。

private void connectionFailed() :连接失败的时候处理,通知 ui ,并设为

STATE_LISTEN 状态。

private void connectionLost() :当连接失去的时候,设为 STATE_LISTEN 状态并通

知 UI 。

内部类:

private class AcceptThread extends Thread :创建监听线程,准备接受新连接。使

用阻塞方式,调用 () 。提供 cancel 方法关闭 socket 。

private class ConnectThread extends Thread :这是定义的连接线程,专门用来对

外发出连接对方蓝牙的请求和处理流程。构造函数里通过

RfcommSocketToServiceRecord(),从待连接的 device 产生

BluetoothSocket. 然后在 run 方法中 connect ,成功后调用 BluetoothChatSevice 的

connected() 方法。定义 cancel() 在关闭线程时能够关闭相关 socket 。

private class ConnectedThread extends Thread :这个是双方蓝牙连接后一直运行

的线程。构造函数中设置输入输出流。 Run 方法中使用阻塞模式的 () 循

环读取输入流, 然后 post 到UI 线程中更新聊天消息。也提供了 write() 将聊天消息写

入输出流传输至对方,传输成功后回写入 UI 线程。最后 cancel() 关闭连接的 socket 。

该类包含 UI 和操作的 Activity 类,作用是得到系统默认蓝牙设备的已配对设备列

表,以及搜索出的未配对的新设备的列表。然后提供点击后发出连接设备请求的功能。

BluetoothDevice 类,此为对应的远程蓝牙 Device

createRfcommSocketToServiceRecord() :创建该 Device 的 socket 。

BluetoothSocket 类

connect() :请求连接蓝牙。

getInputStream() :得到输入流,用于接收远程方信息。

getOutputStream() :得到输出流,发送给远程方的信息。

close() :关闭蓝牙连接。

InputStream 类:

read(byte[]) :以阻塞方式读取输入流。

OutputStream 类:

write(byte[]) :将信息写入该输出流,发送给远程。

有关Bluetooth的英文文档如下所示:

Bluetooth

The Android platform includes support for the Bluetooth network stack, which allows

a device to wirelessly exchange data with other Bluetooth devices. The application

framework provides access to the Bluetooth functionality through the Android

Bluetooth APIs. These APIs let applications wirelessly connect to other Bluetooth

devices, enabling point-to-point and multipoint wireless features.

Using the Bluetooth APIs, an Android application can perform the following:

Scan for other Bluetooth devices

Query the local Bluetooth adapter for paired Bluetooth devices

Establish RFCOMM channels

Connect to other devices through service discovery

Transfer data to and from other devices

Manage multiple connections

All of the Bluetooth APIs are available in the oth package. Here's

a summary of the classes and interfaces you will need to create Bluetooth

connections:

Four major tasks necessary to communicate using Bluetooth: setting up Bluetooth,

finding devices that are either paired or available in the local area, connecting

devices, and transferring data between devices.

BluetoothAdapter

Represents the local Bluetooth adapter (Bluetooth radio).

The BluetoothAdapter is the entry-point for all Bluetooth interaction.

Using this, you can discover other Bluetooth devices, query a list of bonded

(paired) devices, instantiate a BluetoothDevice using a known MAC address,

and create a BluetoothServerSocket to listen for communications from

other devices.

BluetoothDevice

Represents a remote Bluetooth device. Use this to request a connection with

a remote device through a BluetoothSocket or query information about the

device such as its name, address, class, and bonding state.

BluetoothSocket

Represents the interface for a Bluetooth socket (similar to a TCP Socket).

This is the connection point that allows an application to exchange data with

another Bluetooth device via InputStream and OutputStream.

BluetoothServerSocket

Represents an open server socket that listens for incoming requests (similar

to a TCP ServerSocket). In order to connect two Android devices, one device

must open a server socket with this class. When a remote Bluetooth device

makes a connection request to the this device,

the BluetoothServerSocket will return

connected BluetoothSocket when the connection is accepted.

a

BluetoothClass

Describes the general characteristics and capabilities of a Bluetooth device.

This is a read-only set of properties that define the device's major and minor

device classes and its services. However, this does not reliably describe

all Bluetooth profiles and services supported by the device, but is useful

as a hint to the device type.

BluetoothProfile

An interface that represents a Bluetooth profile. A

Bluetooth profile

is

a wireless interface specification for Bluetooth-based communication

between devices. An example is the Hands-Free profile. For more discussion

of profiles, see Working with Profiles

BluetoothHeadset

Provides support for Bluetooth headsets to be used with mobile phones. This

includes both Bluetooth Headset and Hands-Free (v1.5) profiles.

BluetoothA2dp

Defines how high quality audio can be streamed from one device to another

over a Bluetooth connection. "A2DP" stands for Advanced Audio Distribution

Profile.

eListener

An interface that notifies BluetoothProfile IPC clients when they have

been connected to or disconnected from the service (that is, the internal

service that runs a particular profile).

Bluetooth Permissions

In order to use Bluetooth features in your application, you need to declare at least

one of two Bluetooth permissions: BLUETOOTH and BLUETOOTH_ADMIN.

Declare the Bluetooth permission(s) in your application manifest file. For example:

...

Setting Up Bluetooth

1. Get the BluetoothAdapter

BluetoothAdapter mBluetoothAdapter = aultAdapter();

if (mBluetoothAdapter == null) {

// Device does not support Bluetooth

}

2. Enable Bluetooth

if (!led()) {

Intent enableBtIntent =

Intent(_REQUEST_ENABLE);

startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

}

Finding Devices

Using the BluetoothAdapter, you can find remote Bluetooth devices either through

device discovery or by querying the list of paired (bonded) devices.

Note: Android-powered devices are not discoverable by default. A user can make the

device discoverable for a limited time through the system settings, or an application

can request that the user enable discoverability without leaving the application.

How to enable discoverability is discussed below.

Querying paired devices

Before performing device discovery, its worth querying the set of paired devices

to see if the desired device is already known. To do so, call getBondedDevices().

This will return a Set ofBluetoothDevices representing paired devices. For example,

you can query all paired devices and then show the name of each device to the user,

using an ArrayAdapter:

Set pairedDevices = dedDevices();

// If there are paired devices

if (() > 0) {

// Loop through paired devices

for (BluetoothDevice device : pairedDevices) {

// Add the name and address to an array adapter to show in a ListView

(e() + "n" + ress());

}

}

All that's needed from the BluetoothDevice object in order to initiate a

connection is the MAC address. In this example, it's saved as a part of an

new

ArrayAdapter that's shown to the user. The MAC address can later be extracted in

order to initiate the connection.

Discovering devices

// Create a BroadcastReceiver for ACTION_FOUND

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

public void onReceive(Context context, Intent intent) {

String action = ion();

// When discovery finds a device

if (_(action)) {

// Get the BluetoothDevice object from the Intent

BluetoothDevice device =

celableExtra(_DEVICE);

// Add the name and address to an array adapter to show in a

ListView

(e() + "n" +

ress());

}

}

};

// Register the BroadcastReceiver

IntentFilter filter = new IntentFilter(_FOUND);

registerReceiver(mReceiver, filter); // Don't forget to unregister during

onDestroy

Enabling discoverability

Intent discoverableIntent = new

Intent(_REQUEST_DISCOVERABLE);

ra(_DISCOVERABLE_DURATION,

300);

startActivity(discoverableIntent);

Note: If Bluetooth has not been enabled on the device, then enabling device

discoverability will automatically enable Bluetooth.

You do not need to enable device discoverability if you will be initiating the

connection to a remote device. Enabling discoverability is only necessary when you

want your application to host a server socket that will accept incoming connections,

because the remote devices must be able to discover the device before it can initiate

the connection.

Connecting Devices

In order to create a connection between your application on two devices, you must

implement both the server-side and client-side mechanisms, because one device must

open a server socket and the other one must initiate the connection (using the server

device's MAC address to initiate a connection).

The server device and the client device each obtain the

required BluetoothSocket in different ways. The server will receive it when an

incoming connection is accepted. The client will receive it when it opens an RFCOMM

channel to the server.

Note: If the two devices have not been previously paired, then the Android framework

will automatically show a pairing request notification or dialog to the user during

the connection procedure, as shown in Figure 3. So when attempting to connect devices,

your application does not need to be concerned about whether or not the devices are

paired. Your RFCOMM connection attempt will block until the user has successfully

paired, or will fail if the user rejects pairing, or if pairing fails or times out.

Connecting as a server

When you want to connect two devices, one must act as a server by holding an

open BluetoothServerSocket. The purpose of the server socket is to listen for

incoming connection requests and when one is accepted, provide a

connected BluetoothSocket. When the BluetoothSocket is acquired from

theBluetoothServerSocket, the BluetoothServerSocket can (and should) be

discarded, unless you want to accept more connections.

Here's the basic procedure to set up a server socket and accept a connection:

1. Get a BluetoothServerSocket by calling

the listenUsingRfcommWithServiceRecord(String, UUID).

2. Start listening for connection requests by calling accept().

3. Unless you want to accept additional connections, call close().

The accept() call should not be executed in the main Activity UI thread because

it is a blocking call and will prevent any other interaction with the application.

It usually makes sense to do all work with

a BluetoothServerSocket or BluetoothSocket in a new thread managed by your

application. To abort a blocked call such as accept(), call close() on

the BluetoothServerSocket (orBluetoothSocket) from another thread and the

blocked call will immediately return. Note that all methods on

a BluetoothServerSocket or BluetoothSocket are thread-safe.

Example

Here's a simplified thread for the server component that accepts incoming

connections:

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 =

UsingRfcommWithServiceRecord(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 = ();

} catch (IOException e) {

break;

}

// If a connection was accepted

if (socket != null) {

// Do work to manage the connection (in a separate

thread)

manageConnectedSocket(socket);

();

break;

}

}

}

/** Will cancel the listening socket, and cause the thread to finish */

public void cancel() {

try {

();

} catch (IOException e) { }

}

}

Connecting as a client

Here's the basic procedure:

the BluetoothDevice, get a BluetoothSocket by

calling createRfcommSocketToServiceRecord(UUID).

2. Initiate the connection by calling connect().

Note: You should always ensure that the device is not performing device discovery

when you call connect(). If discovery is in progress, then the connection attempt

will be significantly slowed and is more likely to fail.

Example

Here is a basic example of a thread that initiates a Bluetooth connection:

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 = RfcommSocketToServiceRecord(MY_UUID);

} catch (IOException e) { }

mmSocket = tmp;

}

public void run() {

// Cancel discovery because it will slow down the connection

Discovery();

try {

}

// Connect the device through the socket. This will block

// until it succeeds or throws an exception

t();

} catch (IOException connectException) {

// Unable to connect; close the socket and get out

try {

();

} 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 {

();

} catch (IOException e) { }

}

Managing a Connection

When you have successfully connected two (or more) devices, each one will have a

connected BluetoothSocket. This is where the fun begins because you can share data

between devices. Using theBluetoothSocket, the general procedure to transfer

arbitrary data is simple:

1. Get the InputStream and OutputStream that handle transmissions through the

socket, via getInputStream() and getOutputStream(), respectively.

2. Read and write data to the streams with read(byte[]) and write(byte[]).

Example

Here's an example of how this might look:

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 = utStream();

tmpOut = putStream();

} 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 = (buffer);

// Send the obtained bytes to the UI Activity

Message(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 {

(bytes);

} catch (IOException e) { }

}

}

/* Call this from the main Activity to shutdown the connection */

public void cancel() {

try {

();

} catch (IOException e) { }

}

BluetoothAdapter

Represents the local Bluetooth adapter (Bluetooth radio).

The BluetoothAdapter is the entry-point for all Bluetooth interaction.

Using this, you can discover other Bluetooth devices, query a list of bonded

(paired) devices, instantiate a BluetoothDevice using a known MAC address,

and create a BluetoothServerSocket to listen for communications from

other devices.

BluetoothDevice

Represents a remote Bluetooth device. Use this to request a connection with

a remote device through a BluetoothSocket or query information about the

device such as its name, address, class, and bonding state.

BluetoothSocket

Represents the interface for a Bluetooth socket (similar to a TCP Socket).

This is the connection point that allows an application to exchange data with

another Bluetooth device via InputStream and OutputStream.

BluetoothServerSocket

Represents an open server socket that listens for incoming requests (similar

to a TCP ServerSocket). In order to connect two Android devices, one device

must open a server socket with this class. When a remote Bluetooth device

makes a connection request to the this device,

the BluetoothServerSocket will return a

connected BluetoothSocket when the connection is accepted.

BluetoothClass

Describes the general characteristics and capabilities of a Bluetooth device.

This is a read-only set of properties that define the device's major and minor

device classes and its services. However, this does not reliably describe

all Bluetooth profiles and services supported by the device, but is useful

as a hint to the device type.

BluetoothProfile

An interface that represents a Bluetooth profile. A

Bluetooth profile

is

a wireless interface specification for Bluetooth-based communication

between devices. An example is the Hands-Free profile. For more discussion

of profiles, see Working with Profiles

BluetoothHeadset

Provides support for Bluetooth headsets to be used with mobile phones. This

includes both Bluetooth Headset and Hands-Free (v1.5) profiles.

BluetoothA2dp

Defines how high quality audio can be streamed from one device to another

over a Bluetooth connection. "A2DP" stands for Advanced Audio Distribution

Profile.

eListener

An interface that notifies BluetoothProfile IPC clients when they have

been connected to or disconnected from the service (that is, the internal

service that runs a particular profile).

To get a BluetoothAdapter representing the local Bluetooth adapter, call the

static getDefaultAdapter() method. Fundamentally, this is your starting point

for all Bluetooth actions. Once you have the local adapter, you can get a set

of BluetoothDevice objects representing all paired devices

with getBondedDevices(); start device discovery with startDiscovery(); or create

a BluetoothServerSocket to listen for incoming connection requests

with listenUsingRfcommWithServiceRecord(String, UUID).

Note: Most methods require the BLUETOOTH permission and some also require

the BLUETOOTH_ADMIN permission.

To get a BluetoothDevice, use oteDevice(String) to

create one representing a device of a known MAC address (which you can get through

device discovery withBluetoothAdapter) or get one from the set of bonded devices

returned by dedDevices(). You can then open

a BluetoothSocket for communication with the remote device,

using createRfcommSocketToServiceRecord(UUID).

Note: Requires the BLUETOOTH permission.

The interface for Bluetooth Sockets is similar to that of TCP

sockets: Socket and ServerSocket. On the server side, use

a BluetoothServerSocket to create a listening server socket. When a connection

is accepted by the BluetoothServerSocket, it will return a

new BluetoothSocket to manage the connection. On the client side, use a

single BluetoothSocket to both initiate an outgoing connection and to manage

the connection.

To create a BluetoothSocket for connecting to a known device,

use RfcommSocketToServiceRecord(). Then

call connect() to attempt a connection to the remote device. This call will

block until a connection is established or the connection fails.

BluetoothSocket is thread safe. In particular, close() will always

immediately abort ongoing operations and close the socket.

Note: Requires the BLUETOOTH permission.

On the server side, use a BluetoothServerSocket to create a listening server

socket. When a connection is accepted by the BluetoothServerSocket, it will

return a new BluetoothSocket to manage the connection. On the client side, use

a single BluetoothSocket to both initiate an outgoing connection and to manage

the connection.

To create a listening BluetoothServerSocket that's ready for incoming

connections, use UsingRfcommWithServiceRecord(). Then