Android Bluetooth Low Energy (Android Low-power Bluetooth)

Source: Internet
Author: User

Android Bluetooth Low Energy (Android Low-power Bluetooth)

Android 4.3 (API Level 18) has introduced core functions of Bluetooth Low Energy (BLE, Low-power Bluetooth) and provided relevant APIs through which applications can scan devices and query services, characteristics (attribute feature) of a read/write device ). Compared with traditional Bluetooth, BLE can significantly reduce power consumption. This makes low-power communication between Android applications and BLE devices possible, such as distance sensors, heart rate monitors, and fitness devices.


1. Key terms and concepts
1.1 The following is a summary of some of BLE's key terms and concepts:



* Generic Attribute Profile (GATT ):GATT profile is a general specification for sending and receiving short data segments. Such short data segments are known as "attributes" on BLE connections. Currently, the profile of all low-power applications is based on GATT. In addition, the Bluetooth Technology Alliance (Bluetooth SIG) has defined profiles for many BLE devices. Profile is a specification that defines how a device works in a specified application. Note: One device can implement multiple profiles. For example, a device can contain a heart rate monitor and a battery detector.
* Attribute Protocol (ATT, Attribute Protocol ):GATT is built on the basis of ATT, so it is always GATT/ATT. ATT optimizes the running of BLE devices. To this end, it will try to use less bytes of data. Each attribute is uniquely identified by UUID. UUID is a string ID in the standard 128-bit format. It is used to uniquely identify an information. Properties are formatted as characteristics and services by ATT protocol for transmission.
* Characteristic:A characteristic contains a value, and 0 or more descriptors used to describe the characteristic value. Characteristic can be considered as a type, similar to a class.
* Descriptor:The attribute defined in Descriptor (Descriptor) is used to describe a characteristic value. For example, a descriptor can specify a readable description within an acceptable range for a characteristic value or a measurement unit for a characteristic value.
* Service:
A service is a characteristic set. For example, you can hold a service named "heart rate monitor", which contains characteristic words such as "Heart Rate Measurement ". You can find a series of GATT-based profiles and services on mongoth.org.


1.2 roles and functions

The following are some applicable roles and functions for an Android device to interact with a BLE device:


* Central and peripheral devices.This applies to the connection of BLE itself. Devices that act as central devices are responsible for scanning and searching for advertisements, while devices that act as peripheral devices are responsible for advertising.

* GATT server and GATT client.This depends on how the two devices communicate with each other after the connection is established.


To understand the difference, imagine that you have an Android phone and a BLE device as an Activity Tracker. The mobile phone will act as the central device, and the Activity Tracker will act as the peripheral device (you need to have two roles to establish a BLE connection, both of which are the peripheral device roles and cannot communicate with each other, both of them serve as central devices and cannot communicate with each other ).


Once the mobile phone is connected to the Activity Tracker, they can transmit GATT media data to each other. Based on the data they transmit, one party must assume the role of the server. For example, if an Activity Tracker wants to send sensor data to a mobile phone, the Activity Tracker must assume a server role. If the Activity Tracker wants to receive data from the mobile phone, the mobile phone must assume the role of the server.


In this document, the Android Application (running on Android devices) is the GATT client. The application obtains data from the GATT server, which is composed of BLE Heart Rate monitor devices that support Heart Rate Profile. However, you can turn your Android Application to assume the role of the GATT server. For more information, see BluetoothGattService.


2. BLE Permissions (BLE permission)

To use the Bluetooth function in your application, you must declareAndroid. permission. BLUETOOTHPermission. You need this permission to perform some Bluetooth communication operations, such as request links, accept connections, and transmit data.


If you want your application to scan devices or manage Bluetooth settings, you must declareAndroid. permission. javasth_adminPermission. Note: If you use the th_admin permission, you must declare the BLUETOOTH permission at the same time.


Declare the Bluetooth permission in your application manifest file.

If you want to declare that your application can only run on a device that supports BLE, You can include the following statement in your application manifest file:

However, if you want your application to run on devices that do not support BLE, you should set the attribute in the above tag to required = "false ". Then, the PackageManager. hasSystemFeature () method is used during the running process to determine whether the device supports BLE:

// use the following methods to determine if the device supports BLE, then you can choose to disable BLE
If (! GetPackageManager (). HasSystemFeature (PackageManager. FEATURE_BLUETOOTH_LE)) {
Toast. MakeText (this, R.s tring ble_not_supported, Toast. LENGTH_SHORT), show ();
Finish ();
}

3. Setting Up BLE (set BLE)

Before your application communicates through BLE, you need to confirm whether the device supports BLE. If yes, check whether it is enabled. Note that this check step is only available in It must be executed only when it is set to false.


If BLE is not supported, You Should elegantly disable some BLE functions. If BLE is supported but disabled, You need to request the user to enable Bluetooth without leaving your application state. This process must be completed in two steps:


3.1 obtain the thadapter.


Basically, all activities that use Bluetooth require a thadapter. Descrithadapter represents the Bluetooth adapter (Bluetooth sending receiver) of the device ). There is a thadapter object in the system. Your application can use this object for interaction. The following code snippet shows how to obtain the adapter. Note that the following method uses the getSystemService () method to obtain a thmanager instance, and then obtains the thadapter through thmanager. Android 4.3 (API Level 18) starts to support javasthmanager:

// initialize the bluetooth adapter.
Final BluetoothManager BluetoothManager =
(BluetoothManager) getSystemService (Context. BLUETOOTH_SERVICE);
MBluetoothAdapter = bluetoothManager. GetAdapter ();

3.2 enable Bluetooth

Next, make sure that the Bluetooth is enabled. Call the isEnable () method to check whether Bluetooth is currently enabled. If the method returns false, Bluetooth is disabled. In the following code snippet, check whether Bluetooth is enabled. If it is not enabled, the code snippet will display an error prompting you to enable Bluetooth:

Private BluetoothAdapter mBluetoothAdapter;
.
// confirm that the device supports bluetooth and is enabled. If not,
// a dialog box displays asking the user for authorization to enable bluetooth.
If (mBluetoothAdapter == null ||! MBluetoothAdapter. IsEnabled ()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
StartActivityForResult (enableBtIntent REQUEST_ENABLE_BT);
}

4. Finding BLE Devices (search for BLE Devices)

Search for BLE devices. You can use the startLeScan () method. This method requires a thadapter. LeScanCallback object as the parameter. You must implement this callback interface because the scan result will be returned through this interface. Because the search device consumes a lot of power, you should follow the following guidelines:


*Once you find the target device, you should immediately stop searching.

*Do not perform endless search and set the maximum search time. A previously accessible device may have been out of the detectable range, and continuing scanning will only consume power.


The following code snippet shows how to start and stop a search:

/ * *
* scan and display the Activity of an accessible BLE device.
* /
Public class DeviceScanActivity extends ListActivity {

Private BluetoothAdapter mBluetoothAdapter;
Private Boolean mScanning;
Private Handler mHandler;

// stop scanning after 10 seconds.
Private static final long SCAN_PERIOD = 10000;
.
Private void scanLeDevice(final Boolean enable) {
If (enable) {
// stop scanning after a predefined scan time period.
The mHandler. PostDelayed (new Runnable () {
@ Override
Public void the run () {
MScanning = false;
MBluetoothAdapter. StopLeScan (mLeScanCallback);
}
}, SCAN_PERIOD);

MScanning = true;
MBluetoothAdapter. StartLeScan (mLeScanCallback);
} else {
MScanning = false;
MBluetoothAdapter. StopLeScan (mLeScanCallback);
}
.
}
.
}

If you only want to search for peripheral devices of the specified type, you can replace them with startLeScan (UUID [], BluetoothAdapter. and provides an array of UUID objects for the GATT service supported by your application.


The following is an implementation of javasthadapter. LeScanCallback, which is an interface used to receive BLE search results:

Private LeDeviceListAdapter mLeDeviceListAdapter;
.
// device search callback interface.
Private BluetoothAdapter. LeScanCallback mLeScanCallback =
New BluetoothAdapter. LeScanCallback () {
@ Override
Public void onLeScan(final BluetoothDevice device, int rssi,
Byte [] scanRecord) {
RunOnUiThread (new Runnable () {
@ Override
Public void the run () {
MLeDeviceListAdapter. AddDevice (device);
MLeDeviceListAdapter. NotifyDataSetChanged ();
}
});
}
};

Note: As described in the Bluetooth document, you can only search for BLE devices or traditional Bluetooth devices at the same time. You cannot search for BLE devices and traditional Bluetooth devices at the same time.


5. Connecting to a GATT Server (connect to a GATT Service)

The first step in interacting with a BLE device is to connect to it-more accurately, it is to connect to the GATT service on the device. You can use the connectGatt () method to connect to the GATT service on the BLE device. This method requires three parameters: a Context object, autoConnect (a boolean value indicating whether to automatically connect when the BLE device is accessible), and javasthgattcallbackduixiang:


mBluetoothGatt = device.connectGatt(this, false, mGattCallback);


The above code will connect to the GATT service managed by the BLE device and return a gatethgatt instance. Through this instance, you can perform operations on the GATT client. The caller (Android Application) is the GATT client. The gatethgattcallback object is used to deliver the operation results to the client, such as the connection status and the results of some future GATT client operations.


In this example, the BLE application provides a DeviceControlActivity to connect and display data, and display the GATT service and characteristic supported by the BLE device. Based on the user input, this activity will communicate with a Service named javasthleservice, which interacts with the BLE device through the Android ble api.

// a service that interacts with BLE devices through the Android BLE API.
Public class BluetoothLeService extends Service {
Private final static String TAG = BluetoothLeService. Class. GetSimpleName ();

Private BluetoothManager mBluetoothManager;
Private BluetoothAdapter mBluetoothAdapter;
Private String mBluetoothDeviceAddress;
Private BluetoothGatt mBluetoothGatt;
Private int mConnectionState = STATE_DISCONNECTED;

Private static final int STATE_DISCONNECTED = 0;
Private static final int STATE_CONNECTING = 1;
Private static final int STATE_CONNECTED = 2;

Public final static String ACTION_GATT_CONNECTED =
"Com. Example. Bluetooth. Le. ACTION_GATT_CONNECTED";
Public final static String ACTION_GATT_DISCONNECTED =
"Com. Example. Bluetooth. Le. ACTION_GATT_DISCONNECTED";
Public final static String ACTION_GATT_SERVICES_DISCOVERED =
"Com. Example. Bluetooth. Le. ACTION_GATT_SERVICES_DISCOVERED";
Public final static String ACTION_DATA_AVAILABLE =
"Com. Example. Bluetooth. Le. ACTION_DATA_AVAILABLE";
Public final static String EXTRA_DATA =
"Com. Example. Bluetooth. Le. EXTRA_DATA";

Public final static UUID UUID_HEART_RATE_MEASUREMENT =
UUID. FromString (SampleGattAttributes. HEART_RATE_MEASUREMENT);

// the various callback methods defined by the BLE API.
Private final BluetoothGattCallback mGattCallback =
New BluetoothGattCallback () {
@ Override
Public void onConnectionStateChange(bluetooth thgatt gatt, int status,
Int newState because) {
String intentAction;
If (newState == bluetooth profile.state_connected) {
IntentAction = ACTION_GATT_CONNECTED;
MConnectionState = STATE_CONNECTED;
BroadcastUpdate (intentAction);
Log. I (TAG, "connection GATT service ");
Log. I (TAG, "try to start service search :" +
MBluetoothGatt. DiscoverServices ());

} else if (newState == bluetoothprofile.state_disconnected) {
IntentAction = ACTION_GATT_DISCONNECTED;
MConnectionState = STATE_DISCONNECTED;
Log. I (TAG, "disconnect GATT server ");
BroadcastUpdate (intentAction);
}
}

@ Override
/ / New services the discovered
Public void onServicesDiscovered(BluetoothGatt gatt, int status) {
If (status == bluetooth bf.gatt_success) {
BroadcastUpdate (ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: "+ status);
}
}

@ Override
// Result of a characteristic read operation
Public void onCharacteristicRead (BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
Int status) {
If (status == bluetooth bf.gatt_success) {
BroadcastUpdate (ACTION_DATA_AVAILABLE, characteristic);
}
}
.
};
.
}

When a specific callback method is called, it will call the broadcastUpdate () Help method appropriately and pass an operation identifier. Note that the data in this section is parsed according to the profile specification of Bluetooth Heart Rate Measurement:


Private void broadcastUpdate(final String action) {
Final Intent Intent = new Intent(action);
SendBroadcast (intent);
}

Private void broadcastUpdate(final String action,
Final BluetoothGattCharacteristic characteristic) {
Final Intent Intent = new Intent(action);

// specific treatment according to profile of heart rate measurement.
// data is parsed according to a profile specification.
If (UUID_HEART_RATE_MEASUREMENT. Equals (characteristic. GetUuid ())) {
Int flag = characteristic. The getProperties ();
Int the format = 1;
If ((flag & 0x01)! = 0) {
Format = BluetoothGattCharacteristic. FORMAT_UINT16;
Log. D (TAG, "Heart rate format UINT16.");
} else {
Format = BluetoothGattCharacteristic. FORMAT_UINT8;
Log. D (TAG, "Heart rate format UINT8.");
}
Final int heartRate = characteristic. GetIntValue (format, 1);
Format ("Received heart rate: %d", heartRate);
Intent. PutExtra (EXTRA_DATA, String. The valueOf (heartRate));
} else {
// for other profiles, format the data to 16 disabled data.
Final byte[] data = characteristic. GetValue ();
If (data! = null && data.length > 0) {
Final StringBuilder StringBuilder = new StringBuilder(data.length);
For (byte byteChar: data)
StringBuilder. Append (the String. Format (" % 02 x, "byteChar));
Intent.putextra (EXTRA_DATA, new String(data) + "\n" +
The stringBuilder. ToString ());
}
}
SendBroadcast (intent);
}



Return to DeviceControlActivity. The following events are handled by a BroadcaseReceiver:

// handle the various times the Service is sent.
// ACTION_GATT_CONNECTED: a GATT service is connected.
// ACTION_GATT_DISCONNECTED: disconnected from a GATT service.
// ACTION_GATT_SERVICES_DISCOVERED: GATT service discovered.
// ACTION_DATA_AVAILABLE: receive data from the device. This may be the result of a read or notification operation.
Private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
@ Override
Public void onReceive(Context, Intent Intent) {
Final String action = intent. GetAction ();
If (BluetoothLeService. ACTION_GATT_CONNECTED. Equals (action)) {
MConnected = true;
UpdateConnectionState (R.s tring. Connected);
InvalidateOptionsMenu ();
} else if (BluetoothLeService. ACTION_GATT_DISCONNECTED. Equals (action)) {
MConnected = false;
UpdateConnectionState (R.s tring. Disconnected);
InvalidateOptionsMenu ();
ClearUI ();
} else if (BluetoothLeService.
ACTION_GATT_SERVICES_DISCOVERED. Equals (action)) {
// show all supported services and characteristics.
DisplayGattServices (mBluetoothLeService getSupportedGattServices ());
} else if (BluetoothLeService. ACTION_DATA_AVAILABLE. Equals (action)) {
DisplayData (intent. GetStringExtra (BluetoothLeService EXTRA_DATA));
}
}
};

6. Reading BLE Attribute (read the BLE Attribute)

Once your Android Application connects to a GATT service and discovers a service on the device, you can read and write properties in a location that supports read and write. For example, the following code snippets iterate the service and characteristic of the service and display them on the interface:


Public class DeviceControlActivity extends Activity {
.
/ / how to support by iterative GATT Services/Characteristics.
// in this example, we populate the data structure bound to ExpandableListView.
Private void displayGattServices(List gattServices) {
If (gattServices == null) return;
String uuid = null;
String unknownServiceString = getResources ().
Get string (R.s tring. Unknown_service);
String unknownCharaString = getResources ().
Get string (R.s tring. Unknown_characteristic);
ArrayList > gattServiceData =
New ArrayList > ();
ArrayList > > gattCharacteristicData
= new ArrayList > > ();
MGattCharacteristics =
New ArrayList > ();

// circular iteration of accessible GATT Services.
Bluetooth BluetoothGattService: bluetooth services {
A HashMap currentServiceData =
New HashMap ();
Uuid = gattService. GetUuid (). The toString ();
CurrentServiceData. Put (
SampleGattAttributes LIST_NAME.
Lookup (uuid, unknownServiceString));
CurrentServiceData. Put (LIST_UUID, uuid);
GattServiceData. Add (currentServiceData);

ArrayList > gattCharacteristicGroupData =
New ArrayList > ();
The List gattCharacteristics =
GattService. GetCharacteristics ();
ArrayList charas =
New ArrayList ();
// loop iteration accessible Characteristics.
For (BluetoothGattCharacteristic gattCharacteristic:
GattCharacteristics) {
Charas. Add (gattCharacteristic);
A HashMap currentCharaData =
New HashMap ();
Uuid = gattCharacteristic. GetUuid (). The toString ();
CurrentCharaData. Put (
LIST_NAME, SampleGattAttributes. Lookup (uuid,
UnknownCharaString));
CurrentCharaData. Put (LIST_UUID, uuid);
GattCharacteristicGroupData. Add (currentCharaData);
}
MGattCharacteristics. Add (charas);
GattCharacteristicData. Add (gattCharacteristicGroupData);
}
.
}
.
}
  
   
> GattServiceData = new ArrayList
   
    
> (); ArrayList> gattCharacteristicData = new ArrayList> (); mGattCharacteristics = new ArrayList> (); // cyclically iterates the accessible GATT Services. for (gatethgattservice gattService: gattServices) {HashMap
private BluetoothGatt mBluetoothGatt;
BluetoothGattCharacteristic characteristic;
boolean enabled;
...
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
...
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
        UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
CurrentServiceData = new HashMap (); Uuid = gattService. getUuid (). toString (); currentServiceData. put (LIST_NAME, SampleGattAttributes. lookup (uuid, unknownServiceString); currentServiceData. put (LIST_UUID, uuid); gattServiceData. add (currentServiceData); ArrayList > GattCharacteristicGroupData = new ArrayList > (); ListGattCharacteristics = gattService. getCharacteristics (); ArrayListCharas = new ArrayList(); // Characteristics that can be accessed by loop iteration. for (descrithgattcharacteristic gattCharacteristic: gattCharacteristics) {charas. add (gattCharacteristic); HashMap CurrentCharaData = new HashMap (); Uuid = gattCharacteristic. getUuid (). toString (); currentCharaData. put (LIST_NAME, SampleGattAttributes. lookup (uuid, unknownCharaString); currentCharaData. put (LIST_UUID, uuid); gattCharacteristicGroupData. add (currentCharaData);} mGattCharacteristics. add (charas); gattCharacteristicData. add (gattCharacteristicGroupData );}...}...}



7. Receiving GATT Notification)

It is common for BLE applications to receive notifications when a specified characteristic change of the device occurs. The following code snippet shows how to set a notification for a characteristic by using setCharacteristicNotification:

private BluetoothGatt mBluetoothGatt;
BluetoothGattCharacteristic characteristic;
boolean enabled;
...
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
...
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
        UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);

Once a notification is enabled for a characteristic device, the onCharacteristicChanged () method is triggered when the characteristic device changes:

@Override
// Characteristic notification
public void onCharacteristicChanged(BluetoothGatt gatt,
        BluetoothGattCharacteristic characteristic) {
    broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}

8. Closing the Client App (close the Client application)

Once your application uses the BLE device, you should call the close () method so that the system can properly release the occupied resources:

public void close() {
    if (mBluetoothGatt == null) {
        return;
    }
    mBluetoothGatt.close();
    mBluetoothGatt = null;
}


Address: http://developer.android.com/guide/topics/connectivity/bluetooth-le.html




Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.