This document details the API that applications can use to interface with Bluetooth LE (Low Energy) profiles implemented by certain Motorola Mobility devices. This API is intended for use by applications that provide a user interface to the LE profiles; it is not used to implement the profile itself. All of the data processing for a specific profile happens in the profile implemented by Motorola. Applications only use the computed data and present it to the user. The Bluetooth Low Energy API allows an application to connect to a remote device on a specific LE profile and perform read and write operations in adherence to the profile specification. All error handling is done in the profile layer: appropriate error codes are sent to the application using Intents.
Application requirements
Applications using the Bluetooth Low Energy API must meet the following requirements:
- Applications must use standard Android API for non-LE Bluetooth operations such as device discovery and Bluetooth device pairing.
- Data received by and sent to the application must conform to the profile specification. Application requirements that fall outside the profile specification may not be supported.
The application must register a callback with the profile (during connect) to receive user data from the peer device.
Classes used by applications
Applications that interact with a Bluetooth LE device (such as a heart rate monitor) typically rely upon the following classes:
-
android.bluetooth.BluetoothDevice -
android.bluetooth.BluetoothClass -
android.bluetooth.BluetoothAdapter -
com.motorola.bluetooth.hrm.IBluetoothHrm -
com.motorola.bluetooth.hrm.IBluetoothHrmCallback -
com.motorola.bluetoothle.BluetoothGatt
The android.bluetooth classes are part of the Android SDK. The com.motorola.bluetooth... classes are packaged in the MotBTLE_API_stubs.jar library file (which can be found in the SDK add-on for devices that support this API); add this JAR file to your project in order to use them. You do this by opening your project's properties, navigating to Java Build Path, clicking the Libraries tab, and then using either Add JARs (if the JAR file is among the files that make up your project) or Add External JARs (if the JAR file is on your development computer but not within your project).
Architecture
The following architecture diagram shows how the components are placed in the Android space. Third-party applications use the API described in this document to communicate with the LE profiles.
Basic heart rate use case
- User invokes the Heart Rate app on their phone.
- The app triggers the Heart Profile Service (Connect MSC).
- The app/user scans for LE devices, then pairs and connects to it (Connect MSC).
- Based on the app configuration, the heart rate data is received from the peer device at every interval using callbacks. (Receive Data MSC).
- Received data is displayed by the app to the user. This data format needs to be negotiated for each profile implementation. For HRM we have Beats Per Minute, Energy Expended, R-R Intervals, sent in the data argument as an array of bytes.
IBluetoothHrm methods used by applications
connectLe
int connectLe (BluetoothDevice device, String service, IBluetoothHrmCallback callback)
Connects to a remote LE device. Before invoking this method you must have used the Android Bluetooth API to discover and pair with a device. This method requires you to supply the device address of the remote LE device and the UUID of the profile/service to which your app is to connect. You also supply a callback object, which receives user data sent from the peer device. See IBluetoothHrmCallback interface for information on the callback object.
This method is asynchronous: after calling it you need to wait for confirmation of the disconnection, which is delivered using an Intent with its action set to the following:
BluetoothGatt.CONNECT_COMPLETE ("com.motorola.bluetoothle.bluetoothgatt.CONNECT_COMPLETE")
This Intent includes the following extra data:
| Extra name | Data type | Data |
|---|---|---|
"device"
|
BluetoothDevice
|
Address of the remote device that was connected. |
"uuid"
|
String
|
UUID of the service that was connected. |
"status"
|
int
|
An integer status code: one of the values listed under Status codes. |
Parameters
- device
- address of the remote device being connected to.
- service
- UUID of the service to which your app is to connect.
- callback
- IBluetoothHRMCallback object that receives user data from the connected device/service.
Returns
An integer status code: one of the values listed under Status codes.
disconnectLe
int disconnectLe (BluetoothDevice device, String service)
Disconnects from a remote LE device. You must supply the address of the remote LE device and the UUID of the profile/service from which you want to disconnect.
This method is asynchronous: after calling it you need to wait for confirmation of the disconnection, which is delivered using an Intent with its action set to the following:
BluetoothGatt.DISCONNECT_COMPLETE ("com.motorola.bluetoothle.bluetoothgatt.DISCONNECT_COMPLETE")
This Intent includes the following extra data:
| Extra name | Data type | Data |
|---|---|---|
"device"
|
BluetoothDevice
|
Address of the remote device that was disconnected. |
"uuid"
|
String
|
UUID of the service that was disconnected. |
"status"
|
int
|
An integer status code: one of the values listed under Status codes. |
Parameters
- device
- address of the remote device from which the app is to disconnect.
- service
- UUID of the service from which the app is to disconnect.
Returns
An integer status code: one of the values listed under Status codes.
getLeData
int getLeData (BluetoothDevice device, String service, int operationType)
Obtains data from a remote LE device. You must supply the address of the remote LE device, the UUID of the profile/service from which you want to get data, and the type of operation to be performed (from the list under OperationType values).
This method is asynchronous: after calling it you need to wait for confirmation, which is delivered using an Intent with its action set to the following:
BluetoothGatt.GET_COMPLETE ("com.motorola.bluetoothle.bluetoothgatt.GET_COMPLETE")
This Intent not only confirms the operation but, if the operation was successful, also contains the requested data. It includes the following extra data:
| Extra name | Data type | Data |
|---|---|---|
"device"
|
BluetoothDevice
|
Address of the remote device from which the data was sent. |
"uuid"
|
String
|
UUID of the service that sent the data. |
"status"
|
int
|
An integer status code: one of the values listed under Status codes. |
"length"
|
int
|
The number of bytes of data that was sent. |
"data"
|
byte[]
|
The data. |
Parameters
- device
- address of the remote device with which your app is communicating.
- service
- UUID of the service with which your app is communicating.
- operationType
- an integer indicating the operation to be performed: one of the values from the list under OperationType values.
Returns
An integer status code: one of the values listed under Status codes.
setLeData
int setLeData (BluetoothDevice device, String service, int operationType, byte [] data, int length)
Writes data to a remote LE device. You must supply the address of the remote LE device and the UUID of the profile/service to which you want to write data. You also supply an operation type (a 16-bit unsigned integer from the list under OperationType values) and the data to be written.
This method is asynchronous: after calling it you need to wait for confirmation, which is delivered using an Intent with its action set to the following:
BluetoothGatt.SET_COMPLETE ("com.motorola.bluetoothle.bluetoothgatt.SET_COMPLETE")
This Intent includes the following extra data:
| Extra name | Data type | Data |
|---|---|---|
"device"
|
BluetoothDevice
|
Address of the remote device to which the data was sent. |
"uuid"
|
String
|
UUID of the service to which the data was sent. |
"status"
|
int
|
An integer status code: one of the values listed under Status codes. |
Parameters
- device
- address of the remote device with which your app is communicating.
- service
- UUID of the service with which your app is communicating.
- operationType
- an integer indicating the operation to be performed: one of the values from the list under OperationType values.
- data
- the data to be written to the specified device/service.
- length
- the length of data, in bytes.
Returns
An integer status code: one of the values listed under Status codes.
IBluetoothHrmCallback interface
Data sent from a Bluetooth LE device is sent to a registered object that implements the IBluetoothHrmCallback interface. Per the GATT profile specification, data can be received either as an Indication or as a Notification. Accordingly, the callback should implement both of the following methods and should expect data to come in through either.
indicationLeCb
void indicationLeCb (in BluetoothDevice device, String service, in int length, in Byte [] data)
Parameters
- device
- address of the remote device from which the data was sent.
- service
- UUID of the service from which the data was sent.
- length
- length of the sent data, in bytes.
- data
- the data.
notificationLeCb
void notificationLeCb (in BluetoothDevice device, String service, in int length, in byte [] data)
Parameters
- device
- address of the remote device from which the data was sent.
- service
- UUID of the service from which the data was sent.
- length
- length of the sent data, in bytes.
- data
- the data.
OperationType values
The following enums represent different operation types that apps can use to perform read or write operations. These enum values cover all operations as defined by the GATT profile for Bluetooth LE and are extensible if needed.
| Constant | Value |
|---|---|
OPERATION_READ_PRIMARY_SERVICES
|
0 |
OPERATION_READ_CHARACTERISTICS
|
1 |
OPERATION_RESET_ENERGY_EXPENDED
|
2 |
OPERATION_READ_SENSOR_LOCATION
|
3 |
OPERATION_ENABLE_INDICATION
|
4 |
OPERATION_ENABLE_NOTIFICATION
|
5 |
OPERATION_DISABLE_INDICATION
|
6 |
OPERATION_DISABLE_NOTIFICATION
|
7 |
Status codes
The following codes indicate the status of an operation. These status codes are used both as API return values and as status in the Intents.
| Constant | Value |
|---|---|
SUCCESS
|
0 |
PENDING
|
1 |
CONNECTION_EXISTS
|
2 |
FAILURE
|
3 |
INVALID_OPERATION
|
4 |
FORBIDDEN
|
5 |
SERVICE_UNAVAILABLE
|
6 |
UNKNOWN_ERROR
|
7 |
Other constants
| Constant | Value | Description |
|---|---|---|
EXTRA_PRIMARY_UUID
|
"com.motorola.bluetoothle.bluetoothgatt.extra.PRIMARY_UUID" |
Key used for extra data containing the heart rate monitor UUID; use this when constructing a BluetoothGatt.ACTION_START_LE intent.
|
HRM data format
The HRM data is passed from the HRM profile to the app through the notificationLeCb callback. The data is delivered as an array of bytes and should be interpreted by the application as follows:
| Bytes | Description |
|---|---|
| 0-1 | The heart rate measurement value. A value of 0 in byte 1 indicates the incoming heart rate data is an unsigned 8-bit integer. |
| 2-3 | The energy expended value. A value of 0 implies energy expended data is not supported by the heart rate sensor. The maximum energy expended value can be 0xFFFF. If the app receives this maximum value it needs to provide the user with an option to reset the energy expended. |
| 4-n | The R-R interval values. The application needs to calculate the number of R-R interval values sent based on the total length of incoming data. If the length of the incoming data is 4 it implies the R-R interval values are not present. |
Using the heart rate monitor profile
To use the above API for a heart rate monitor application, the following needs to be done:
- Import the following aidl files in the app's source code:
-
com.motorola.bluetooth.hrm.IBluetoothHrm -
com.motorola.bluetooth.hrm.IBluetoothHrmCallback -
com.motorola.bluetoothle.BluetoothGatt
-
- Bind to the HRM service using the
IBluetoothHrminterface:Intent intent1 = new Intent(IBluetoothHrm.class.getName()); getApplicationContext().bindService(intent1, mConnection, Context.BIND_AUTO_CREATE);
- In your code that handles the service connection, invoke the
connectLe()method and pass anHrmCallbackobject as an argument:callback callback1 = new callback(hrmUUID); ... mHrmService = IBluetoothHrm.Stub.asInterface(service); ... int status = mHrmService.connectLe(device1, hrmUUID, callback1);
- Start the
BluetoothGattservice, passing it the service UUID for the heart rate monitor:Intent intent2 = new Intent(BluetoothGatt.ACTION_START_LE); intent2.putExtra(BluetoothGatt.EXTRA_PRIMARY_UUID, hrmUUID); sendBroadcast(intent2);
Message sequence diagrams
Connect
Disconnect
Get data
Set data
Receiving user data from peer device
Checking for Bluetooth LE support
At runtime, apps can check for Bluetooth Low Energy support by verifying the presence of the BluetoothGattService class, like this:
try {
@SuppressWarnings("unused")
Class object = Class.forName("android.server.BluetoothGattService");
deviceSupportsLE = true;
} catch (Exception e) {
deviceSupportsLE = false;
}
References
-
- Core Version 4.0 (Low Energy)
- GATT Profile Specification
- Android Bluetooth API definitions
Created: November 14, 2011
ECCN 5D992.a: In accordance with United States Export Administration Regulations (EAR), and specifically the Commerce Control List (CCL), this item has been classified 5D992.a. Export or re-export of this commodity and compliance with the U.S. Export Administration Regulations is ultimately the responsibility of the exporter. For more detailed information related to export or re-export of this item, please consult the EAR at http://www.access.gpo.gov/bis/ear/ear_data.html.
Copyright © 2011, Motorola Mobility, Inc. All rights reserved unless otherwise explicitly indicated. Sample source code written by Motorola Mobility, Inc. is provided to you under the conditions of the Motorola Modified BSD License.

