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