blob: 5c32e56146a6dda35c0264ec2f49f70fd088f8f1 [file] [log] [blame]
kmccormickf14ff1c2013-06-06 11:14:57 -07001page.title=Bluetooth Low Energy
Joe Fernandez33baa5a2013-11-14 11:41:19 -08002page.tags=wireless,bluetoothadapter,bluetoothdevice,BLE,BTLE
kmccormickf14ff1c2013-06-06 11:14:57 -07003@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
Scott Main64fedb72013-11-12 09:12:38 -080047<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
kmccormickf14ff1c2013-06-06 11:14:57 -070056
57<p>
58Android 4.3 (API Level 18) introduces built-in platform support for Bluetooth Low
59Energy in the <em>central role</em> and provides APIs that apps can use to discover
60devices, query for services, and read/write characteristics.
61In contrast to
62<a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Classic Bluetooth</a>,
63Bluetooth Low Energy (BLE) is designed to provide significantly lower power consumption.
64This allows Android apps to communicate with BLE devices that have low power requirements,
65such 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>&mdash;The GATT profile
71is a general specification for sending and receiving short pieces of data known
72as "attributes" over a BLE link. All current Low Energy application profiles are
73based 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>
77for Low Energy devices. A profile is a specification for how a device works in a
78particular application. Note that a device can implement more than one profile.
79For example, a device could contain a heart rate monitor and a battery level
80detector.</li>
81 </ul>
82 </li>
83 <li><strong>Attribute Protocol (ATT)</strong>&mdash;GATT is built on top of
84the Attribute Protocol (ATT). This is also referred to as GATT/ATT. ATT is
85optimized to run on BLE devices. To this end, it uses as few bytes as possible.
86Each attribute is uniquely identified by a Universally Unique Identifier (UUID),
87which is a standardized 128-bit format for a string ID used to uniquely
88identify information. The <em>attributes</em> transported by ATT are formatted
89as <em>characteristics</em> and <em>services</em>. </li>
90
91 <li><strong>Characteristic</strong>&mdash;A characteristic contains a single
92value and 0-n descriptors that describe the characteristic's value. A
93characteristic can be thought of as a type, analogous to a class. </li>
94 <li><strong>Descriptor</strong>&mdash;Descriptors are defined attributes that
95describe a characteristic value. For example, a descriptor might specify a
96human-readable description, an acceptable range for a characteristic's value, or
97a unit of measure that is specific to a characteristic's value.</li>
98
99 <li><strong>Service</strong>&mdash;A service is a collection of
100characteristics. For example, you could have a service called
101&quot;Heart Rate Monitor&quot; that includes characteristics such as
102&quot;heart rate measurement.&quot; You can find a list of existing GATT-based
103profiles and services on
104<a href="https://www.bluetooth.org/en-us/specification/adopted-specifications">
105bluetooth.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
112an 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
119other once they've established the connection.</li>
120</ul>
121
122<p>To understand the distinction, imagine that you have an Android phone and
123an activity tracker that is a BLE device. The phone supports the
124central role; the activity tracker supports the peripheral role (to
125establish a BLE connection you need one of each&mdash;two things that only support
126peripheral couldn't talk to each other, nor could two things that only support
127central).</p>
128
129<p>Once the phone and the activity tracker have established a connection, they
130start transferring GATT metadata to one another. Depending on the kind of data they transfer,
131one or the other might act as the server. For example, if the activity tracker
132wants to report sensor data to the phone, it might make sense for the activity
133tracker to act as the server. If the activity tracker wants to receive updates
134from the phone, then it might make sense for the phone to act
135as the server.</p>
136
137<p>
138In the example used in this document, the Android app (running on an Android
139device) is the GATT client. The app gets data from the GATT server, which is a
140BLE heart rate monitor that supports the
141<a href="http://developer.bluetooth.org/TechnologyOverview/Pages/HRP.aspx">Heart
142Rate Profile</a>. But you could alternatively design
143your Android app to play the GATT server
144role. See {@link android.bluetooth.BluetoothGattServer} for more
145information.</p>
146
147<h2 id="permissions">BLE Permissions</h2>
148
149<p>In order to use Bluetooth features in your application, you must declare
150the Bluetooth permission {@link android.Manifest.permission#BLUETOOTH}.
151You need this permission to perform any Bluetooth communication,
152such 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
155settings, you must also declare the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
156permission. <strong>Note:</strong> If you use the
157{@link android.Manifest.permission#BLUETOOTH_ADMIN} permission, then you must
158also have the {@link android.Manifest.permission#BLUETOOTH} permission.</p>
159
160<p>Declare the Bluetooth permission(s) in your application manifest file. For
161example:</p>
162
163<pre>
164&lt;uses-permission android:name=&quot;android.permission.BLUETOOTH&quot;/&gt;
165&lt;uses-permission android:name=&quot;android.permission.BLUETOOTH_ADMIN&quot;/&gt;</pre>
166
167<p>If you want to declare that your app is available to BLE-capable devices only,
168include the following in your app's manifest:</p>
169
170<pre>&lt;uses-feature android:name=&quot;android.hardware.bluetooth_le&quot; android:required=&quot;true&quot;/&gt;
171</pre>
172
173<p>However, if you want to make your app available to devices that don't support BLE,
174you should still include this element in your app's manifest, but set {@code required="false"}.
175Then 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.
180if (!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
188to verify that BLE is supported on the device, and if so, ensure that it is enabled.
189Note that this check is only necessary if {@code &lt;uses-feature.../&gt;}
190is set to false.</p>
191
192<p>If BLE is not supported, then you should gracefully disable any
193BLE features. If BLE is supported, but disabled, then you can request that the
194user enable Bluetooth without leaving your application. This setup is
195accomplished 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
202Bluetooth activity. The {@link android.bluetooth.BluetoothAdapter} represents
203the device's own Bluetooth adapter (the Bluetooth radio). There's one Bluetooth
204adapter for the entire system, and your application can interact with it using
205this object. The snippet below shows how to get the adapter. Note that this approach
206uses {@link android.content.Context#getSystemService getSystemService()} to return
207an instance of {@link android.bluetooth.BluetoothManager}, which is then
208used to get the adapter. Android 4.3 (API Level 18) introduces
209{@link android.bluetooth.BluetoothManager}:</p>
210
211<pre>// Initializes Bluetooth adapter.
212final BluetoothManager bluetoothManager =
213 (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
214mBluetoothAdapter = bluetoothManager.getAdapter();
215</pre>
216</li>
217
218<li>Enable Bluetooth
219<p>Next, you need to ensure that Bluetooth is enabled. Call {@link
220android.bluetooth.BluetoothAdapter#isEnabled()} to check whether Bluetooth is
221currently enabled. If this method returns false, then Bluetooth is disabled.
222The following snippet checks whether Bluetooth is enabled. If it isn't, the
223snippet displays an error prompting the user to go to Settings to enable
224Bluetooth:</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.
229if (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.
242This method takes a {@link android.bluetooth.BluetoothAdapter.LeScanCallback}
243as a parameter. You must implement this callback, because that is how scan
244results are returned. Because scanning is battery-intensive, you should observe
245the 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
249previously available may have moved out of range, and continuing to scan drains
250the 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 */
258public 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 &#64;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
291call {@link android.bluetooth.BluetoothAdapter#startLeScan startLeScan(UUID[], BluetoothAdapter.LeScanCallback)},
292providing an array of {@link java.util.UUID} objects that specify the GATT
293services your app supports.</p>
294
295<p>Here is an implementation of the
296{@link android.bluetooth.BluetoothAdapter.LeScanCallback},
297which is the interface used to deliver BLE scan results:</p>
298
299<pre>
300private LeDeviceListAdapter mLeDeviceListAdapter;
301...
302// Device scan callback.
303private BluetoothAdapter.LeScanCallback mLeScanCallback =
304 new BluetoothAdapter.LeScanCallback() {
305 &#64;Override
306 public void onLeScan(final BluetoothDevice device, int rssi,
307 byte[] scanRecord) {
308 runOnUiThread(new Runnable() {
309 &#64;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
322scan 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&mdash;
327more specifically, connecting to the GATT server on the device. To
328connect to a GATT server on a BLE device, you use the
329{@link android.bluetooth.BluetoothDevice#connectGatt connectGatt()} method.
330This method takes three parameters: a {@link android.content.Context} object,
331<code>autoConnect</code> (boolean indicating whether to automatically connect to
332the 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
339conduct GATT client operations. The caller (the Android app) is the GATT client.
340The {@link android.bluetooth.BluetoothGattCallback} is used to deliver results
341to the client, such as connection status, as well as any further GATT client
342operations.</p>
343
344<p>In this example, the BLE app provides an activity
345(<code>DeviceControlActivity</code>) to connect,
346display data, and display GATT services and characteristics
347supported by the device. Based on user input, this activity communicates with a
348{@link android.app.Service} called {@code BluetoothLeService},
349which 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.
353public 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 &#64;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 &#64;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 &#64;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
429parsing in this section is performed in accordance with the Bluetooth Heart Rate
430Measurement
431<a href="http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml">
432profile specifications</a>:</p>
433
434<pre>private void broadcastUpdate(final String action) {
435 final Intent intent = new Intent(action);
436 sendBroadcast(intent);
437}
438
439private 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 &amp; 0x01) != 0) {
449 format = BluetoothGattCharacteristic.FORMAT_UINT16;
450 Log.d(TAG, &quot;Heart rate format UINT16.&quot;);
451 } else {
452 format = BluetoothGattCharacteristic.FORMAT_UINT8;
453 Log.d(TAG, &quot;Heart rate format UINT8.&quot;);
454 }
455 final int heartRate = characteristic.getIntValue(format, 1);
456 Log.d(TAG, String.format(&quot;Received heart rate: %d&quot;, 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 &amp;&amp; data.length &gt; 0) {
462 final StringBuilder stringBuilder = new StringBuilder(data.length);
463 for(byte byteChar : data)
464 stringBuilder.append(String.format(&quot;%02X &quot;, byteChar));
465 intent.putExtra(EXTRA_DATA, new String(data) + &quot;\n&quot; +
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.
483private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
484 &#64;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,
511it can read and write attributes, where supported. For example, this snippet iterates
512through the server's services and characteristics and displays them in the UI:</p>
513
514<pre>
515public 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&lt;BluetoothGattService&gt; 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&lt;HashMap&lt;String, String&gt;&gt; gattServiceData =
529 new ArrayList&lt;HashMap&lt;String, String&gt;&gt;();
530 ArrayList&lt;ArrayList&lt;HashMap&lt;String, String&gt;&gt;&gt; gattCharacteristicData
531 = new ArrayList&lt;ArrayList&lt;HashMap&lt;String, String&gt;&gt;&gt;();
532 mGattCharacteristics =
533 new ArrayList&lt;ArrayList&lt;BluetoothGattCharacteristic&gt;&gt;();
534
535 // Loops through available GATT Services.
536 for (BluetoothGattService gattService : gattServices) {
537 HashMap&lt;String, String&gt; currentServiceData =
538 new HashMap&lt;String, String&gt;();
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&lt;HashMap&lt;String, String&gt;&gt; gattCharacteristicGroupData =
547 new ArrayList&lt;HashMap&lt;String, String&gt;&gt;();
548 List&lt;BluetoothGattCharacteristic&gt; gattCharacteristics =
549 gattService.getCharacteristics();
550 ArrayList&lt;BluetoothGattCharacteristic&gt; charas =
551 new ArrayList&lt;BluetoothGattCharacteristic&gt;();
552 // Loops through available Characteristics.
553 for (BluetoothGattCharacteristic gattCharacteristic :
554 gattCharacteristics) {
555 charas.add(gattCharacteristic);
556 HashMap&lt;String, String&gt; currentCharaData =
557 new HashMap&lt;String, String&gt;();
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
576characteristic changes on the device. This snippet shows how to set a notification
577for a characteristic, using the
578{@link android.bluetooth.BluetoothGatt#setCharacteristicNotification setCharacteristicNotification()}
579method:</p>
580
581<pre>
582private BluetoothGatt mBluetoothGatt;
583BluetoothGattCharacteristic characteristic;
584boolean enabled;
585...
586mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
587...
588BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
589 UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
590descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
591mBluetoothGatt.writeDescriptor(descriptor);</pre>
592
593<p>Once notifications are enabled for a characteristic,
594an {@link android.bluetooth.BluetoothGattCallback#onCharacteristicChanged onCharacteristicChanged()}
595callback is triggered if the characteristic changes on the remote device:</p>
596
597<pre>&#64;Override
598// Characteristic notification
599public 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()}
609so 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>