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