1 page.title=Bluetooth Low Energy 2 page.tags="wireless","bluetoothadapter","bluetoothdevice","BLE","BTLE" 3 @jd:body 4 5 <div id="qv-wrapper"> 6 <div id="qv"> 7 8 <h2>In this document</h2> 9 <ol> 10 <li><a href="#terms">Key Terms and Concepts</a> 11 <ol> 12 <li><a href="#roles">Roles and Responsibilities</a></li> 13 </ol> 14 </li> 15 <li><a href="#permissions">BLE Permissions</a></li> 16 <li><a href="#setup">Setting Up BLE</a></li> 17 <li><a href="#find">Finding BLE Devices</a></li> 18 <li><a href="#connect">Connecting to a GATT Server</a></li> 19 <li><a href="#read">Reading BLE Attributes</a></li> 20 <li><a href="#notification">Receiving GATT Notifications</a></li> 21 <li><a href="#close">Closing the Client App</a></li> 22 </ol> 23 24 <h2>Key classes</h2> 25 <ol> 26 <li>{@link android.bluetooth.BluetoothGatt}</li> 27 <li>{@link android.bluetooth.BluetoothGattCallback}</li> 28 <li>{@link android.bluetooth.BluetoothGattCharacteristic}</li> 29 <li>{@link android.bluetooth.BluetoothGattService}</li> 30 </ol> 31 32 <h2>Related samples</h2> 33 <ol> 34 <li><a href="{@docRoot}tools/samples/index.html">Bluetooth LE sample</a></li> 35 </ol> 36 37 <h2>See Also</h2> 38 <ol> 39 <li><a href="http://developers.google.com/events/io/sessions/326240948"> 40 Best Practices for Bluetooth Development</a> (video)</li> 41 42 </ol> 43 44 </div> 45 </div> 46 47 48 <p> 49 Android 4.3 (API Level 18) introduces built-in platform support for Bluetooth Low 50 Energy in the <em>central role</em> and provides APIs that apps can use to discover 51 devices, query for services, and read/write characteristics. 52 In contrast to 53 <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Classic Bluetooth</a>, 54 Bluetooth Low Energy (BLE) is designed to provide significantly lower power consumption. 55 This allows Android apps to communicate with BLE devices that have low power requirements, 56 such as proximity sensors, heart rate monitors, fitness devices, and so on.</p> 57 58 <h2 id="terms">Key Terms and Concepts</h2> 59 <p>Here is a summary of key BLE terms and concepts:</p> 60 <ul> 61 <li><strong>Generic Attribute Profile (GATT)</strong>—The GATT profile 62 is a general specification for sending and receiving short pieces of data known 63 as "attributes" over a BLE link. All current Low Energy application profiles are 64 based on GATT. 65 <ul> 66 <li>The Bluetooth SIG defines many 67 <a href="https://www.bluetooth.org/en-us/specification/adopted-specifications">profiles</a> 68 for Low Energy devices. A profile is a specification for how a device works in a 69 particular application. Note that a device can implement more than one profile. 70 For example, a device could contain a heart rate monitor and a battery level 71 detector.</li> 72 </ul> 73 </li> 74 <li><strong>Attribute Protocol (ATT)</strong>—GATT is built on top of 75 the Attribute Protocol (ATT). This is also referred to as GATT/ATT. ATT is 76 optimized to run on BLE devices. To this end, it uses as few bytes as possible. 77 Each attribute is uniquely identified by a Universally Unique Identifier (UUID), 78 which is a standardized 128-bit format for a string ID used to uniquely 79 identify information. The <em>attributes</em> transported by ATT are formatted 80 as <em>characteristics</em> and <em>services</em>. </li> 81 82 <li><strong>Characteristic</strong>—A characteristic contains a single 83 value and 0-n descriptors that describe the characteristic's value. A 84 characteristic can be thought of as a type, analogous to a class.</li> 85 <li><strong>Descriptor</strong>—Descriptors are defined attributes that 86 describe a characteristic value. For example, a descriptor might specify a 87 human-readable description, an acceptable range for a characteristic's value, or 88 a unit of measure that is specific to a characteristic's value.</li> 89 90 <li><strong>Service</strong>—A service is a collection of 91 characteristics. For example, you could have a service called 92 "Heart Rate Monitor" that includes characteristics such as 93 "heart rate measurement." You can find a list of existing GATT-based 94 profiles and services on 95 <a href="https://www.bluetooth.org/en-us/specification/adopted-specifications"> 96 bluetooth.org</a>.</li> 97 98 </ul> 99 100 <h3 id="roles">Roles and Responsibilities</h3> 101 102 <p>Here are the roles and responsibilities that apply when 103 an Android device interacts with a BLE device:</p> 104 105 <ul> 106 <li>Central vs. peripheral. This applies to the BLE connection itself. The 107 device in the central role scans, looking for advertisement, and the device in 108 the peripheral role makes the advertisement.</li> 109 <li>GATT server vs. GATT client. This determines how two devices talk to each 110 other once they've established the connection.</li> 111 </ul> 112 113 <p>To understand the distinction, imagine that you have an Android phone and 114 an activity tracker that is a BLE device. The phone supports the 115 central role; the activity tracker supports the peripheral role (to 116 establish a BLE connection you need one of each—two things that only support 117 peripheral couldn't talk to each other, nor could two things that only support 118 central).</p> 119 120 <p>Once the phone and the activity tracker have established a connection, they 121 start transferring GATT metadata to one another. Depending on the kind of data they transfer, 122 one or the other might act as the server. For example, if the activity tracker 123 wants to report sensor data to the phone, it might make sense for the activity 124 tracker to act as the server. If the activity tracker wants to receive updates 125 from the phone, then it might make sense for the phone to act 126 as the server.</p> 127 128 <p> 129 In the example used in this document, the Android app (running on an Android 130 device) is the GATT client. The app gets data from the GATT server, which is a 131 BLE heart rate monitor that supports the 132 <a href="http://developer.bluetooth.org/TechnologyOverview/Pages/HRP.aspx">Heart 133 Rate Profile</a>. But you could alternatively design 134 your Android app to play the GATT server 135 role. See {@link android.bluetooth.BluetoothGattServer} for more 136 information.</p> 137 138 <h2 id="permissions">BLE Permissions</h2> 139 140 <p>In order to use Bluetooth features in your application, you must declare 141 the Bluetooth permission {@link android.Manifest.permission#BLUETOOTH}. 142 You need this permission to perform any Bluetooth communication, 143 such as requesting a connection, accepting a connection, and transferring data.</p> 144 145 <p>If you want your app to initiate device discovery or manipulate Bluetooth 146 settings, you must also declare the {@link android.Manifest.permission#BLUETOOTH_ADMIN} 147 permission. <strong>Note:</strong> If you use the 148 {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission, then you must 149 also have the {@link android.Manifest.permission#BLUETOOTH} permission.</p> 150 151 <p>Declare the Bluetooth permission(s) in your application manifest file. For 152 example:</p> 153 154 <pre> 155 <uses-permission android:name="android.permission.BLUETOOTH"/> 156 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/></pre> 157 158 <p>If you want to declare that your app is available to BLE-capable devices only, 159 include the following in your app's manifest:</p> 160 161 <pre><uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> 162 </pre> 163 164 <p>However, if you want to make your app available to devices that don't support BLE, 165 you should still include this element in your app's manifest, but set {@code required="false"}. 166 Then at run-time you can determine BLE availability by using 167 {@link android.content.pm.PackageManager#hasSystemFeature PackageManager.hasSystemFeature()}: 168 169 <pre>// Use this check to determine whether BLE is supported on the device. Then 170 // you can selectively disable BLE-related features. 171 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { 172 Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); 173 finish(); 174 }</pre> 175 176 <h2 id="setup">Setting Up BLE</h2> 177 178 <p>Before your application can communicate over BLE, you need 179 to verify that BLE is supported on the device, and if so, ensure that it is enabled. 180 Note that this check is only necessary if {@code <uses-feature.../>} 181 is set to false.</p> 182 183 <p>If BLE is not supported, then you should gracefully disable any 184 BLE features. If BLE is supported, but disabled, then you can request that the 185 user enable Bluetooth without leaving your application. This setup is 186 accomplished in two steps, using the {@link android.bluetooth.BluetoothAdapter}. 187 </p> 188 189 190 <ol> 191 <li>Get the {@link android.bluetooth.BluetoothAdapter} 192 <p>The {@link android.bluetooth.BluetoothAdapter} is required for any and all 193 Bluetooth activity. The {@link android.bluetooth.BluetoothAdapter} represents 194 the device's own Bluetooth adapter (the Bluetooth radio). There's one Bluetooth 195 adapter for the entire system, and your application can interact with it using 196 this object. The snippet below shows how to get the adapter. Note that this approach 197 uses {@link android.content.Context#getSystemService getSystemService()} to return 198 an instance of {@link android.bluetooth.BluetoothManager}, which is then 199 used to get the adapter. Android 4.3 (API Level 18) introduces 200 {@link android.bluetooth.BluetoothManager}:</p> 201 202 <pre>// Initializes Bluetooth adapter. 203 final BluetoothManager bluetoothManager = 204 (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 205 mBluetoothAdapter = bluetoothManager.getAdapter(); 206 </pre> 207 </li> 208 209 <li>Enable Bluetooth 210 <p>Next, you need to ensure that Bluetooth is enabled. Call {@link 211 android.bluetooth.BluetoothAdapter#isEnabled()} to check whether Bluetooth is 212 currently enabled. If this method returns false, then Bluetooth is disabled. 213 The following snippet checks whether Bluetooth is enabled. If it isn't, the 214 snippet displays an error prompting the user to go to Settings to enable 215 Bluetooth:</p> 216 <pre>private BluetoothAdapter mBluetoothAdapter; 217 ... 218 // Ensures Bluetooth is available on the device and it is enabled. If not, 219 // displays a dialog requesting user permission to enable Bluetooth. 220 if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { 221 Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 222 startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); 223 } 224 </li> 225 </ol> 226 227 228 229 <h2 id="find">Finding BLE Devices</h2> 230 231 <p>To find BLE devices, you use the 232 {@link android.bluetooth.BluetoothAdapter#startLeScan startLeScan()} method. 233 This method takes a {@link android.bluetooth.BluetoothAdapter.LeScanCallback} 234 as a parameter. You must implement this callback, because that is how scan 235 results are returned. Because scanning is battery-intensive, you should observe 236 the following guidelines:</p> 237 <ul> 238 <li>As soon as you find the desired device, stop scanning.</li> 239 <li>Never scan on a loop, and set a time limit on your scan. A device that was 240 previously available may have moved out of range, and continuing to scan drains 241 the battery.</li> 242 </ul> 243 244 <p>The following snippet shows how to start and stop a scan:</p> 245 246 <pre>/** 247 * Activity for scanning and displaying available BLE devices. 248 */ 249 public class DeviceScanActivity extends ListActivity { 250 251 private BluetoothAdapter mBluetoothAdapter; 252 private boolean mScanning; 253 private Handler mHandler; 254 255 // Stops scanning after 10 seconds. 256 private static final long SCAN_PERIOD = 10000; 257 ... 258 private void scanLeDevice(final boolean enable) { 259 if (enable) { 260 // Stops scanning after a pre-defined scan period. 261 mHandler.postDelayed(new Runnable() { 262 @Override 263 public void run() { 264 mScanning = false; 265 mBluetoothAdapter.stopLeScan(mLeScanCallback); 266 } 267 }, SCAN_PERIOD); 268 269 mScanning = true; 270 mBluetoothAdapter.startLeScan(mLeScanCallback); 271 } else { 272 mScanning = false; 273 mBluetoothAdapter.stopLeScan(mLeScanCallback); 274 } 275 ... 276 } 277 ... 278 } 279 </pre> 280 281 <p>If you want to scan for only specific types of peripherals, you can instead 282 call {@link android.bluetooth.BluetoothAdapter#startLeScan startLeScan(UUID[], BluetoothAdapter.LeScanCallback)}, 283 providing an array of {@link java.util.UUID} objects that specify the GATT 284 services your app supports.</p> 285 286 <p>Here is an implementation of the 287 {@link android.bluetooth.BluetoothAdapter.LeScanCallback}, 288 which is the interface used to deliver BLE scan results:</p> 289 290 <pre> 291 private LeDeviceListAdapter mLeDeviceListAdapter; 292 ... 293 // Device scan callback. 294 private BluetoothAdapter.LeScanCallback mLeScanCallback = 295 new BluetoothAdapter.LeScanCallback() { 296 @Override 297 public void onLeScan(final BluetoothDevice device, int rssi, 298 byte[] scanRecord) { 299 runOnUiThread(new Runnable() { 300 @Override 301 public void run() { 302 mLeDeviceListAdapter.addDevice(device); 303 mLeDeviceListAdapter.notifyDataSetChanged(); 304 } 305 }); 306 } 307 };</pre> 308 309 310 <p class="note"><strong>Note:</strong> You can only scan for Bluetooth LE devices 311 <em>or</em> scan for Classic Bluetooth devices, as described in 312 <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a>. You cannot 313 scan for both Bluetooth LE and classic devices at the same time.</p> 314 315 <h2 id="connect">Connecting to a GATT Server</h2> 316 317 <p>The first step in interacting with a BLE device is connecting to it— 318 more specifically, connecting to the GATT server on the device. To 319 connect to a GATT server on a BLE device, you use the 320 {@link android.bluetooth.BluetoothDevice#connectGatt connectGatt()} method. 321 This method takes three parameters: a {@link android.content.Context} object, 322 <code>autoConnect</code> (boolean indicating whether to automatically connect to 323 the BLE device as soon as it becomes available), and a reference to a 324 {@link android.bluetooth.BluetoothGattCallback}: </p> 325 326 <pre>mBluetoothGatt = device.connectGatt(this, false, mGattCallback);</pre> 327 328 <p>This connects to the GATT server hosted by the BLE device, and returns a 329 {@link android.bluetooth.BluetoothGatt} instance, which you can then use to 330 conduct GATT client operations. The caller (the Android app) is the GATT client. 331 The {@link android.bluetooth.BluetoothGattCallback} is used to deliver results 332 to the client, such as connection status, as well as any further GATT client 333 operations.</p> 334 335 <p>In this example, the BLE app provides an activity 336 (<code>DeviceControlActivity</code>) to connect, 337 display data, and display GATT services and characteristics 338 supported by the device. Based on user input, this activity communicates with a 339 {@link android.app.Service} called {@code BluetoothLeService}, 340 which interacts with the BLE device via the Android BLE API:</p> 341 342 <pre> 343 // A service that interacts with the BLE device via the Android BLE API. 344 public class BluetoothLeService extends Service { 345 private final static String TAG = BluetoothLeService.class.getSimpleName(); 346 347 private BluetoothManager mBluetoothManager; 348 private BluetoothAdapter mBluetoothAdapter; 349 private String mBluetoothDeviceAddress; 350 private BluetoothGatt mBluetoothGatt; 351 private int mConnectionState = STATE_DISCONNECTED; 352 353 private static final int STATE_DISCONNECTED = 0; 354 private static final int STATE_CONNECTING = 1; 355 private static final int STATE_CONNECTED = 2; 356 357 public final static String ACTION_GATT_CONNECTED = 358 "com.example.bluetooth.le.ACTION_GATT_CONNECTED"; 359 public final static String ACTION_GATT_DISCONNECTED = 360 "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED"; 361 public final static String ACTION_GATT_SERVICES_DISCOVERED = 362 "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED"; 363 public final static String ACTION_DATA_AVAILABLE = 364 "com.example.bluetooth.le.ACTION_DATA_AVAILABLE"; 365 public final static String EXTRA_DATA = 366 "com.example.bluetooth.le.EXTRA_DATA"; 367 368 public final static UUID UUID_HEART_RATE_MEASUREMENT = 369 UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT); 370 371 // Various callback methods defined by the BLE API. 372 private final BluetoothGattCallback mGattCallback = 373 new BluetoothGattCallback() { 374 @Override 375 public void onConnectionStateChange(BluetoothGatt gatt, int status, 376 int newState) { 377 String intentAction; 378 if (newState == BluetoothProfile.STATE_CONNECTED) { 379 intentAction = ACTION_GATT_CONNECTED; 380 mConnectionState = STATE_CONNECTED; 381 broadcastUpdate(intentAction); 382 Log.i(TAG, "Connected to GATT server."); 383 Log.i(TAG, "Attempting to start service discovery:" + 384 mBluetoothGatt.discoverServices()); 385 386 } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { 387 intentAction = ACTION_GATT_DISCONNECTED; 388 mConnectionState = STATE_DISCONNECTED; 389 Log.i(TAG, "Disconnected from GATT server."); 390 broadcastUpdate(intentAction); 391 } 392 } 393 394 @Override 395 // New services discovered 396 public void onServicesDiscovered(BluetoothGatt gatt, int status) { 397 if (status == BluetoothGatt.GATT_SUCCESS) { 398 broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); 399 } else { 400 Log.w(TAG, "onServicesDiscovered received: " + status); 401 } 402 } 403 404 @Override 405 // Result of a characteristic read operation 406 public void onCharacteristicRead(BluetoothGatt gatt, 407 BluetoothGattCharacteristic characteristic, 408 int status) { 409 if (status == BluetoothGatt.GATT_SUCCESS) { 410 broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); 411 } 412 } 413 ... 414 }; 415 ... 416 }</pre> 417 418 <p>When a particular callback is triggered, it calls the appropriate 419 {@code broadcastUpdate()} helper method and passes it an action. Note that the data 420 parsing in this section is performed in accordance with the Bluetooth Heart Rate 421 Measurement 422 <a href="http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml"> 423 profile specifications</a>:</p> 424 425 <pre>private void broadcastUpdate(final String action) { 426 final Intent intent = new Intent(action); 427 sendBroadcast(intent); 428 } 429 430 private void broadcastUpdate(final String action, 431 final BluetoothGattCharacteristic characteristic) { 432 final Intent intent = new Intent(action); 433 434 // This is special handling for the Heart Rate Measurement profile. Data 435 // parsing is carried out as per profile specifications. 436 if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { 437 int flag = characteristic.getProperties(); 438 int format = -1; 439 if ((flag & 0x01) != 0) { 440 format = BluetoothGattCharacteristic.FORMAT_UINT16; 441 Log.d(TAG, "Heart rate format UINT16."); 442 } else { 443 format = BluetoothGattCharacteristic.FORMAT_UINT8; 444 Log.d(TAG, "Heart rate format UINT8."); 445 } 446 final int heartRate = characteristic.getIntValue(format, 1); 447 Log.d(TAG, String.format("Received heart rate: %d", heartRate)); 448 intent.putExtra(EXTRA_DATA, String.valueOf(heartRate)); 449 } else { 450 // For all other profiles, writes the data formatted in HEX. 451 final byte[] data = characteristic.getValue(); 452 if (data != null && data.length > 0) { 453 final StringBuilder stringBuilder = new StringBuilder(data.length); 454 for(byte byteChar : data) 455 stringBuilder.append(String.format("%02X ", byteChar)); 456 intent.putExtra(EXTRA_DATA, new String(data) + "\n" + 457 stringBuilder.toString()); 458 } 459 } 460 sendBroadcast(intent); 461 }</pre> 462 463 464 465 <p>Back in <code>DeviceControlActivity</code>, these events are handled by a 466 {@link android.content.BroadcastReceiver}:</p> 467 468 <pre>// Handles various events fired by the Service. 469 // ACTION_GATT_CONNECTED: connected to a GATT server. 470 // ACTION_GATT_DISCONNECTED: disconnected from a GATT server. 471 // ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services. 472 // ACTION_DATA_AVAILABLE: received data from the device. This can be a 473 // result of read or notification operations. 474 private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() { 475 @Override 476 public void onReceive(Context context, Intent intent) { 477 final String action = intent.getAction(); 478 if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) { 479 mConnected = true; 480 updateConnectionState(R.string.connected); 481 invalidateOptionsMenu(); 482 } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) { 483 mConnected = false; 484 updateConnectionState(R.string.disconnected); 485 invalidateOptionsMenu(); 486 clearUI(); 487 } else if (BluetoothLeService. 488 ACTION_GATT_SERVICES_DISCOVERED.equals(action)) { 489 // Show all the supported services and characteristics on the 490 // user interface. 491 displayGattServices(mBluetoothLeService.getSupportedGattServices()); 492 } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { 493 displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA)); 494 } 495 } 496 }; 497 </pre> 498 499 <h2 id="read">Reading BLE Attributes</h2> 500 501 <p>Once your Android app has connected to a GATT server and discovered services, 502 it can read and write attributes, where supported. For example, this snippet iterates 503 through the server's services and characteristics and displays them in the UI:</p> 504 505 <pre> 506 public class DeviceControlActivity extends Activity { 507 ... 508 // Demonstrates how to iterate through the supported GATT 509 // Services/Characteristics. 510 // In this sample, we populate the data structure that is bound to the 511 // ExpandableListView on the UI. 512 private void displayGattServices(List<BluetoothGattService> gattServices) { 513 if (gattServices == null) return; 514 String uuid = null; 515 String unknownServiceString = getResources(). 516 getString(R.string.unknown_service); 517 String unknownCharaString = getResources(). 518 getString(R.string.unknown_characteristic); 519 ArrayList<HashMap<String, String>> gattServiceData = 520 new ArrayList<HashMap<String, String>>(); 521 ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData 522 = new ArrayList<ArrayList<HashMap<String, String>>>(); 523 mGattCharacteristics = 524 new ArrayList<ArrayList<BluetoothGattCharacteristic>>(); 525 526 // Loops through available GATT Services. 527 for (BluetoothGattService gattService : gattServices) { 528 HashMap<String, String> currentServiceData = 529 new HashMap<String, String>(); 530 uuid = gattService.getUuid().toString(); 531 currentServiceData.put( 532 LIST_NAME, SampleGattAttributes. 533 lookup(uuid, unknownServiceString)); 534 currentServiceData.put(LIST_UUID, uuid); 535 gattServiceData.add(currentServiceData); 536 537 ArrayList<HashMap<String, String>> gattCharacteristicGroupData = 538 new ArrayList<HashMap<String, String>>(); 539 List<BluetoothGattCharacteristic> gattCharacteristics = 540 gattService.getCharacteristics(); 541 ArrayList<BluetoothGattCharacteristic> charas = 542 new ArrayList<BluetoothGattCharacteristic>(); 543 // Loops through available Characteristics. 544 for (BluetoothGattCharacteristic gattCharacteristic : 545 gattCharacteristics) { 546 charas.add(gattCharacteristic); 547 HashMap<String, String> currentCharaData = 548 new HashMap<String, String>(); 549 uuid = gattCharacteristic.getUuid().toString(); 550 currentCharaData.put( 551 LIST_NAME, SampleGattAttributes.lookup(uuid, 552 unknownCharaString)); 553 currentCharaData.put(LIST_UUID, uuid); 554 gattCharacteristicGroupData.add(currentCharaData); 555 } 556 mGattCharacteristics.add(charas); 557 gattCharacteristicData.add(gattCharacteristicGroupData); 558 } 559 ... 560 } 561 ... 562 }</pre> 563 564 <h2 id="notification">Receiving GATT Notifications</h2> 565 566 <p>It's common for BLE apps to ask to be notified when a particular 567 characteristic changes on the device. This snippet shows how to set a notification 568 for a characteristic, using the 569 {@link android.bluetooth.BluetoothGatt#setCharacteristicNotification setCharacteristicNotification()} 570 method:</p> 571 572 <pre> 573 private BluetoothGatt mBluetoothGatt; 574 BluetoothGattCharacteristic characteristic; 575 boolean enabled; 576 ... 577 mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); 578 ... 579 BluetoothGattDescriptor descriptor = characteristic.getDescriptor( 580 UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); 581 descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); 582 mBluetoothGatt.writeDescriptor(descriptor);</pre> 583 584 <p>Once notifications are enabled for a characteristic, 585 an {@link android.bluetooth.BluetoothGattCallback#onCharacteristicChanged onCharacteristicChanged()} 586 callback is triggered if the characteristic changes on the remote device:</p> 587 588 <pre>@Override 589 // Characteristic notification 590 public void onCharacteristicChanged(BluetoothGatt gatt, 591 BluetoothGattCharacteristic characteristic) { 592 broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); 593 } 594 </pre> 595 596 <h2 id="close">Closing the Client App</h2> 597 598 <p>Once your app has finished using a BLE device, it should call 599 {@link android.bluetooth.BluetoothGatt#close close()} 600 so the system can release resources appropriately:</p> 601 602 <pre>public void close() { 603 if (mBluetoothGatt == null) { 604 return; 605 } 606 mBluetoothGatt.close(); 607 mBluetoothGatt = null; 608 }</pre> 609