blob: 713dbf43d3313f5c2721003651730d31620ee234 [file] [log] [blame]
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.bluetooth;
18
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080019import android.content.Context;
Jakub Pawlowskib0f64742017-04-21 03:49:00 -070020import android.os.Handler;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080021import android.os.ParcelUuid;
22import android.os.RemoteException;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080023import android.util.Log;
24
25import java.util.ArrayList;
26import java.util.List;
27import java.util.UUID;
28
29/**
Matthew Xieddf7e472013-03-01 18:41:02 -080030 * Public API for the Bluetooth GATT Profile.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080031 *
Matthew Xieddf7e472013-03-01 18:41:02 -080032 * <p>This class provides Bluetooth GATT functionality to enable communication
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080033 * with Bluetooth Smart or Smart Ready devices.
34 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -070035 * <p>To connect to a remote peripheral device, create a {@link BluetoothGattCallback}
Matthew Xie33ec9842013-04-03 00:29:27 -070036 * and call {@link BluetoothDevice#connectGatt} to get a instance of this class.
Matthew Xieddf7e472013-03-01 18:41:02 -080037 * GATT capable devices can be discovered using the Bluetooth device discovery or BLE
38 * scan process.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080039 */
40public final class BluetoothGatt implements BluetoothProfile {
41 private static final String TAG = "BluetoothGatt";
42 private static final boolean DBG = true;
Andre Eisenbach55d19e42014-07-18 14:38:36 -070043 private static final boolean VDBG = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080044
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080045 private IBluetoothGatt mService;
Jakub Pawlowskid64bb882017-03-22 11:22:18 -070046 private BluetoothGattCallback mCallback;
Jakub Pawlowskib0f64742017-04-21 03:49:00 -070047 private Handler mHandler;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080048 private int mClientIf;
Matthew Xieddf7e472013-03-01 18:41:02 -080049 private BluetoothDevice mDevice;
50 private boolean mAutoConnect;
Jacky Cheung3854e222016-10-20 13:55:21 -070051 private int mAuthRetryState;
Matthew Xieddf7e472013-03-01 18:41:02 -080052 private int mConnState;
53 private final Object mStateLock = new Object();
Andre Eisenbachcc68cc92014-03-18 14:26:51 -070054 private Boolean mDeviceBusy = false;
Ganesh Ganapathi Battab88fa822014-04-18 10:00:40 -070055 private int mTransport;
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -080056 private int mPhy;
Matthew Xieddf7e472013-03-01 18:41:02 -080057
Jacky Cheung3854e222016-10-20 13:55:21 -070058 private static final int AUTH_RETRY_STATE_IDLE = 0;
59 private static final int AUTH_RETRY_STATE_NO_MITM = 1;
60 private static final int AUTH_RETRY_STATE_MITM = 2;
61
Matthew Xieddf7e472013-03-01 18:41:02 -080062 private static final int CONN_STATE_IDLE = 0;
63 private static final int CONN_STATE_CONNECTING = 1;
64 private static final int CONN_STATE_CONNECTED = 2;
65 private static final int CONN_STATE_DISCONNECTING = 3;
Matthew Xie33ec9842013-04-03 00:29:27 -070066 private static final int CONN_STATE_CLOSED = 4;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080067
68 private List<BluetoothGattService> mServices;
69
Matthew Xieddf7e472013-03-01 18:41:02 -080070 /** A GATT operation completed successfully */
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080071 public static final int GATT_SUCCESS = 0;
72
Matthew Xieddf7e472013-03-01 18:41:02 -080073 /** GATT read operation is not permitted */
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080074 public static final int GATT_READ_NOT_PERMITTED = 0x2;
75
Matthew Xieddf7e472013-03-01 18:41:02 -080076 /** GATT write operation is not permitted */
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080077 public static final int GATT_WRITE_NOT_PERMITTED = 0x3;
78
79 /** Insufficient authentication for a given operation */
80 public static final int GATT_INSUFFICIENT_AUTHENTICATION = 0x5;
81
82 /** The given request is not supported */
83 public static final int GATT_REQUEST_NOT_SUPPORTED = 0x6;
84
85 /** Insufficient encryption for a given operation */
86 public static final int GATT_INSUFFICIENT_ENCRYPTION = 0xf;
87
88 /** A read or write operation was requested with an invalid offset */
89 public static final int GATT_INVALID_OFFSET = 0x7;
90
91 /** A write operation exceeds the maximum length of the attribute */
92 public static final int GATT_INVALID_ATTRIBUTE_LENGTH = 0xd;
93
Andre Eisenbach45a0a1a2014-06-30 11:37:05 -070094 /** A remote device connection is congested. */
Andre Eisenbachdadefda2014-03-28 14:54:53 -070095 public static final int GATT_CONNECTION_CONGESTED = 0x8f;
96
Matthew Xie90ca8072013-05-28 21:06:50 +000097 /** A GATT operation failed, errors other than the above */
98 public static final int GATT_FAILURE = 0x101;
99
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800100 /**
Andre Eisenbach6ce4db02014-07-16 23:02:42 -0700101 * Connection paramter update - Use the connection paramters recommended by the
102 * Bluetooth SIG. This is the default value if no connection parameter update
103 * is requested.
104 */
Andre Eisenbach4072da02014-08-19 17:58:55 -0700105 public static final int CONNECTION_PRIORITY_BALANCED = 0;
Andre Eisenbach6ce4db02014-07-16 23:02:42 -0700106
107 /**
108 * Connection paramter update - Request a high priority, low latency connection.
109 * An application should only request high priority connection paramters to transfer
110 * large amounts of data over LE quickly. Once the transfer is complete, the application
Andre Eisenbach4072da02014-08-19 17:58:55 -0700111 * should request {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED} connectoin parameters
Andre Eisenbach6ce4db02014-07-16 23:02:42 -0700112 * to reduce energy use.
113 */
Andre Eisenbach4072da02014-08-19 17:58:55 -0700114 public static final int CONNECTION_PRIORITY_HIGH = 1;
Andre Eisenbach6ce4db02014-07-16 23:02:42 -0700115
116 /** Connection paramter update - Request low power, reduced data rate connection parameters. */
Andre Eisenbach4072da02014-08-19 17:58:55 -0700117 public static final int CONNECTION_PRIORITY_LOW_POWER = 2;
Andre Eisenbach6ce4db02014-07-16 23:02:42 -0700118
119 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800120 * No authentication required.
121 * @hide
122 */
123 /*package*/ static final int AUTHENTICATION_NONE = 0;
124
125 /**
126 * Authentication requested; no man-in-the-middle protection required.
127 * @hide
128 */
129 /*package*/ static final int AUTHENTICATION_NO_MITM = 1;
130
131 /**
132 * Authentication with man-in-the-middle protection requested.
133 * @hide
134 */
135 /*package*/ static final int AUTHENTICATION_MITM = 2;
136
137 /**
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700138 * Bluetooth GATT callbacks. Overrides the default BluetoothGattCallback implementation.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800139 */
Jakub Pawlowskid7116be2017-03-27 12:14:40 -0700140 private final IBluetoothGattCallback mBluetoothGattCallback =
141 new IBluetoothGattCallback.Stub() {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800142 /**
143 * Application interface registered - app is ready to go
144 * @hide
145 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700146 @Override
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800147 public void onClientRegistered(int status, int clientIf) {
148 if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status
149 + " clientIf=" + clientIf);
Matthew Xieddf7e472013-03-01 18:41:02 -0800150 if (VDBG) {
151 synchronized(mStateLock) {
152 if (mConnState != CONN_STATE_CONNECTING) {
153 Log.e(TAG, "Bad connection state: " + mConnState);
154 }
155 }
156 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800157 mClientIf = clientIf;
Matthew Xieddf7e472013-03-01 18:41:02 -0800158 if (status != GATT_SUCCESS) {
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700159 mHandler.post(new Runnable() {
160 @Override
161 public void run() {
162 mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
163 BluetoothProfile.STATE_DISCONNECTED);
164 }
165 });
166
Matthew Xieddf7e472013-03-01 18:41:02 -0800167 synchronized(mStateLock) {
168 mConnState = CONN_STATE_IDLE;
169 }
170 return;
171 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800172 try {
Matthew Xieddf7e472013-03-01 18:41:02 -0800173 mService.clientConnect(mClientIf, mDevice.getAddress(),
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800174 !mAutoConnect, mTransport, mPhy); // autoConnect is inverse of "isDirect"
Matthew Xieddf7e472013-03-01 18:41:02 -0800175 } catch (RemoteException e) {
176 Log.e(TAG,"",e);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800177 }
178 }
179
180 /**
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800181 * Phy update callback
182 * @hide
183 */
184 @Override
185 public void onPhyUpdate(String address, int txPhy, int rxPhy, int status) {
186 if (DBG) Log.d(TAG, "onPhyUpdate() - status=" + status
187 + " address=" + address + " txPhy=" + txPhy + " rxPhy=" + rxPhy);
188 if (!address.equals(mDevice.getAddress())) {
189 return;
190 }
191
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700192 mHandler.post(new Runnable() {
193 @Override
194 public void run() {
195 mCallback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status);
196 }
197 });
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800198 }
199
200 /**
201 * Phy read callback
202 * @hide
203 */
204 @Override
205 public void onPhyRead(String address, int txPhy, int rxPhy, int status) {
206 if (DBG) Log.d(TAG, "onPhyRead() - status=" + status
207 + " address=" + address + " txPhy=" + txPhy + " rxPhy=" + rxPhy);
208 if (!address.equals(mDevice.getAddress())) {
209 return;
210 }
211
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700212 mHandler.post(new Runnable() {
213 @Override
214 public void run() {
215 mCallback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status);
216 }
217 });
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800218 }
219
220 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800221 * Client connection state changed
222 * @hide
223 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700224 @Override
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800225 public void onClientConnectionState(int status, int clientIf,
226 boolean connected, String address) {
227 if (DBG) Log.d(TAG, "onClientConnectionState() - status=" + status
228 + " clientIf=" + clientIf + " device=" + address);
Matthew Xieddf7e472013-03-01 18:41:02 -0800229 if (!address.equals(mDevice.getAddress())) {
230 return;
231 }
232 int profileState = connected ? BluetoothProfile.STATE_CONNECTED :
233 BluetoothProfile.STATE_DISCONNECTED;
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700234
235 mHandler.post(new Runnable() {
236 @Override
237 public void run() {
238 mCallback.onConnectionStateChange(BluetoothGatt.this, status, profileState);
239 }
240 });
Matthew Xieddf7e472013-03-01 18:41:02 -0800241
242 synchronized(mStateLock) {
243 if (connected) {
244 mConnState = CONN_STATE_CONNECTED;
245 } else {
246 mConnState = CONN_STATE_IDLE;
247 }
248 }
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700249
250 synchronized(mDeviceBusy) {
251 mDeviceBusy = false;
252 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800253 }
254
255 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800256 * Remote search has been completed.
257 * The internal object structure should now reflect the state
258 * of the remote device database. Let the application know that
259 * we are done at this point.
260 * @hide
261 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700262 @Override
Jakub Pawlowskibf0faed2016-03-01 18:50:27 -0800263 public void onSearchComplete(String address, List<BluetoothGattService> services,
264 int status) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800265 if (DBG) Log.d(TAG, "onSearchComplete() = Device=" + address + " Status=" + status);
Matthew Xieddf7e472013-03-01 18:41:02 -0800266 if (!address.equals(mDevice.getAddress())) {
267 return;
268 }
Jakub Pawlowskibf0faed2016-03-01 18:50:27 -0800269
270 for (BluetoothGattService s : services) {
271 //services we receive don't have device set properly.
272 s.setDevice(mDevice);
273 }
274
275 mServices.addAll(services);
276
277 // Fix references to included services, as they doesn't point to right objects.
278 for (BluetoothGattService fixedService : mServices) {
279 ArrayList<BluetoothGattService> includedServices =
280 new ArrayList(fixedService.getIncludedServices());
281 fixedService.getIncludedServices().clear();
282
283 for(BluetoothGattService brokenRef : includedServices) {
284 BluetoothGattService includedService = getService(mDevice,
285 brokenRef.getUuid(), brokenRef.getInstanceId(), brokenRef.getType());
286 if (includedService != null) {
287 fixedService.addIncludedService(includedService);
288 } else {
289 Log.e(TAG, "Broken GATT database: can't find included service.");
290 }
291 }
292 }
293
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700294 mHandler.post(new Runnable() {
295 @Override
296 public void run() {
297 mCallback.onServicesDiscovered(BluetoothGatt.this, status);
298 }
299 });
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800300 }
301
302 /**
303 * Remote characteristic has been read.
304 * Updates the internal value.
305 * @hide
306 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700307 @Override
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700308 public void onCharacteristicRead(String address, int status, int handle, byte[] value) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -0700309 if (VDBG) Log.d(TAG, "onCharacteristicRead() - Device=" + address
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700310 + " handle=" + handle + " Status=" + status);
311
Matthew Xieddf7e472013-03-01 18:41:02 -0800312 if (!address.equals(mDevice.getAddress())) {
313 return;
314 }
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700315
316 synchronized(mDeviceBusy) {
317 mDeviceBusy = false;
318 }
319
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800320 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
321 || status == GATT_INSUFFICIENT_ENCRYPTION)
Jacky Cheung3854e222016-10-20 13:55:21 -0700322 && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800323 try {
Jacky Cheung3854e222016-10-20 13:55:21 -0700324 final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) ?
325 AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
326 mService.readCharacteristic(mClientIf, address, handle, authReq);
327 mAuthRetryState++;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800328 return;
329 } catch (RemoteException e) {
330 Log.e(TAG,"",e);
331 }
332 }
333
Jacky Cheung3854e222016-10-20 13:55:21 -0700334 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800335
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700336 BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle);
337 if (characteristic == null) {
338 Log.w(TAG, "onCharacteristicRead() failed to find characteristic!");
339 return;
340 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800341
342 if (status == 0) characteristic.setValue(value);
343
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700344 mHandler.post(new Runnable() {
345 @Override
346 public void run() {
347 mCallback.onCharacteristicRead(BluetoothGatt.this, characteristic, status);
348 }
349 });
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800350 }
351
352 /**
353 * Characteristic has been written to the remote device.
354 * Let the app know how we did...
355 * @hide
356 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700357 @Override
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700358 public void onCharacteristicWrite(String address, int status, int handle) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -0700359 if (VDBG) Log.d(TAG, "onCharacteristicWrite() - Device=" + address
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700360 + " handle=" + handle + " Status=" + status);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800361
Matthew Xieddf7e472013-03-01 18:41:02 -0800362 if (!address.equals(mDevice.getAddress())) {
363 return;
364 }
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700365
366 synchronized(mDeviceBusy) {
367 mDeviceBusy = false;
368 }
369
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700370 BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800371 if (characteristic == null) return;
372
373 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
374 || status == GATT_INSUFFICIENT_ENCRYPTION)
Jacky Cheung3854e222016-10-20 13:55:21 -0700375 && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800376 try {
Jacky Cheung3854e222016-10-20 13:55:21 -0700377 final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) ?
378 AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700379 mService.writeCharacteristic(mClientIf, address, handle,
Jacky Cheung3854e222016-10-20 13:55:21 -0700380 characteristic.getWriteType(), authReq, characteristic.getValue());
381 mAuthRetryState++;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800382 return;
383 } catch (RemoteException e) {
384 Log.e(TAG,"",e);
385 }
386 }
387
Jacky Cheung3854e222016-10-20 13:55:21 -0700388 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800389
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700390 mHandler.post(new Runnable() {
391 @Override
392 public void run() {
393 mCallback.onCharacteristicWrite(BluetoothGatt.this, characteristic, status);
394 }
395 });
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800396 }
397
398 /**
399 * Remote characteristic has been updated.
400 * Updates the internal value.
401 * @hide
402 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700403 @Override
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700404 public void onNotify(String address, int handle, byte[] value) {
405 if (VDBG) Log.d(TAG, "onNotify() - Device=" + address + " handle=" + handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800406
Matthew Xieddf7e472013-03-01 18:41:02 -0800407 if (!address.equals(mDevice.getAddress())) {
408 return;
409 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800410
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700411 BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800412 if (characteristic == null) return;
413
414 characteristic.setValue(value);
415
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700416 mHandler.post(new Runnable() {
417 @Override
418 public void run() {
419 mCallback.onCharacteristicChanged(BluetoothGatt.this, characteristic);
420 }
421 });
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800422 }
423
424 /**
425 * Descriptor has been read.
426 * @hide
427 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700428 @Override
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700429 public void onDescriptorRead(String address, int status, int handle, byte[] value) {
430 if (VDBG) Log.d(TAG, "onDescriptorRead() - Device=" + address + " handle=" + handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800431
Matthew Xieddf7e472013-03-01 18:41:02 -0800432 if (!address.equals(mDevice.getAddress())) {
433 return;
434 }
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700435
436 synchronized(mDeviceBusy) {
437 mDeviceBusy = false;
438 }
439
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700440 BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800441 if (descriptor == null) return;
442
443 if (status == 0) descriptor.setValue(value);
444
445 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
446 || status == GATT_INSUFFICIENT_ENCRYPTION)
Jacky Cheung3854e222016-10-20 13:55:21 -0700447 && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800448 try {
Jacky Cheung3854e222016-10-20 13:55:21 -0700449 final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) ?
450 AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
451 mService.readDescriptor(mClientIf, address, handle, authReq);
452 mAuthRetryState++;
Andre Eisenbachd65e8f42014-07-25 15:16:11 -0700453 return;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800454 } catch (RemoteException e) {
455 Log.e(TAG,"",e);
456 }
457 }
458
Jacky Cheung3854e222016-10-20 13:55:21 -0700459 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800460
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700461 mHandler.post(new Runnable() {
462 @Override
463 public void run() {
464 mCallback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
465 }
466 });
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800467 }
468
469 /**
470 * Descriptor write operation complete.
471 * @hide
472 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700473 @Override
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700474 public void onDescriptorWrite(String address, int status, int handle) {
475 if (VDBG) Log.d(TAG, "onDescriptorWrite() - Device=" + address + " handle=" + handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800476
Matthew Xieddf7e472013-03-01 18:41:02 -0800477 if (!address.equals(mDevice.getAddress())) {
478 return;
479 }
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700480
481 synchronized(mDeviceBusy) {
482 mDeviceBusy = false;
483 }
484
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700485 BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800486 if (descriptor == null) return;
487
488 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
489 || status == GATT_INSUFFICIENT_ENCRYPTION)
Jacky Cheung3854e222016-10-20 13:55:21 -0700490 && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800491 try {
Jacky Cheung3854e222016-10-20 13:55:21 -0700492 final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) ?
493 AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700494 mService.writeDescriptor(mClientIf, address, handle,
Jacky Cheung3854e222016-10-20 13:55:21 -0700495 authReq, descriptor.getValue());
496 mAuthRetryState++;
Andre Eisenbachd65e8f42014-07-25 15:16:11 -0700497 return;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800498 } catch (RemoteException e) {
499 Log.e(TAG,"",e);
500 }
501 }
502
Jacky Cheung3854e222016-10-20 13:55:21 -0700503 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800504
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700505 mHandler.post(new Runnable() {
506 @Override
507 public void run() {
508 mCallback.onDescriptorWrite(BluetoothGatt.this, descriptor, status);
509 }
510 });
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800511 }
512
513 /**
514 * Prepared write transaction completed (or aborted)
515 * @hide
516 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700517 @Override
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800518 public void onExecuteWrite(String address, int status) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -0700519 if (VDBG) Log.d(TAG, "onExecuteWrite() - Device=" + address
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800520 + " status=" + status);
Matthew Xieddf7e472013-03-01 18:41:02 -0800521 if (!address.equals(mDevice.getAddress())) {
522 return;
523 }
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700524
525 synchronized(mDeviceBusy) {
526 mDeviceBusy = false;
527 }
528
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700529 mHandler.post(new Runnable() {
530 @Override
531 public void run() {
532 mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
533 }
534 });
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800535 }
536
537 /**
538 * Remote device RSSI has been read
539 * @hide
540 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700541 @Override
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800542 public void onReadRemoteRssi(String address, int rssi, int status) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -0700543 if (VDBG) Log.d(TAG, "onReadRemoteRssi() - Device=" + address +
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800544 " rssi=" + rssi + " status=" + status);
Matthew Xieddf7e472013-03-01 18:41:02 -0800545 if (!address.equals(mDevice.getAddress())) {
546 return;
547 }
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700548 mHandler.post(new Runnable() {
549 @Override
550 public void run() {
551 mCallback.onReadRemoteRssi(BluetoothGatt.this, rssi, status);
552 }
553 });
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800554 }
Wei Wangf3055892014-03-11 22:22:41 -0700555
556 /**
Andre Eisenbach580b0a12014-03-25 06:31:50 -0700557 * Callback invoked when the MTU for a given connection changes
558 * @hide
559 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700560 @Override
Andre Eisenbach580b0a12014-03-25 06:31:50 -0700561 public void onConfigureMTU(String address, int mtu, int status) {
562 if (DBG) Log.d(TAG, "onConfigureMTU() - Device=" + address +
563 " mtu=" + mtu + " status=" + status);
564 if (!address.equals(mDevice.getAddress())) {
565 return;
566 }
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700567
568 mHandler.post(new Runnable() {
569 @Override
570 public void run() {
571 mCallback.onMtuChanged(BluetoothGatt.this, mtu, status);
572 }
573 });
Wei Wangf3055892014-03-11 22:22:41 -0700574 }
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700575
576 /**
577 * Callback invoked when the given connection is updated
578 * @hide
579 */
580 @Override
581 public void onConnectionUpdated(String address, int interval, int latency,
582 int timeout, int status) {
583 if (DBG) Log.d(TAG, "onConnectionUpdated() - Device=" + address +
584 " interval=" + interval + " latency=" + latency +
585 " timeout=" + timeout + " status=" + status);
586 if (!address.equals(mDevice.getAddress())) {
587 return;
588 }
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700589
590 mHandler.post(new Runnable() {
591 @Override
592 public void run() {
593 mCallback.onConnectionUpdated(BluetoothGatt.this, interval, latency,
594 timeout, status);
595 }
596 });
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700597 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800598 };
599
Jeremy Kleinadc26ec2016-09-27 14:34:33 -0700600 /*package*/ BluetoothGatt(IBluetoothGatt iGatt, BluetoothDevice device,
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800601 int transport, int phy) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800602 mService = iGatt;
603 mDevice = device;
Ganesh Ganapathi Battab88fa822014-04-18 10:00:40 -0700604 mTransport = transport;
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800605 mPhy = phy;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800606 mServices = new ArrayList<BluetoothGattService>();
607
Matthew Xieddf7e472013-03-01 18:41:02 -0800608 mConnState = CONN_STATE_IDLE;
Jacky Cheung3854e222016-10-20 13:55:21 -0700609 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800610 }
611
612 /**
Matthew Xie33ec9842013-04-03 00:29:27 -0700613 * Close this Bluetooth GATT client.
Matthew Xieb30f91e2013-05-29 10:19:06 -0700614 *
615 * Application should call this method as early as possible after it is done with
616 * this GATT client.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800617 */
Matthew Xie33ec9842013-04-03 00:29:27 -0700618 public void close() {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800619 if (DBG) Log.d(TAG, "close()");
620
621 unregisterApp();
Matthew Xie33ec9842013-04-03 00:29:27 -0700622 mConnState = CONN_STATE_CLOSED;
Jacky Cheung3854e222016-10-20 13:55:21 -0700623 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800624 }
625
626 /**
627 * Returns a service by UUID, instance and type.
628 * @hide
629 */
630 /*package*/ BluetoothGattService getService(BluetoothDevice device, UUID uuid,
631 int instanceId, int type) {
632 for(BluetoothGattService svc : mServices) {
633 if (svc.getDevice().equals(device) &&
634 svc.getType() == type &&
635 svc.getInstanceId() == instanceId &&
636 svc.getUuid().equals(uuid)) {
637 return svc;
638 }
639 }
640 return null;
641 }
642
643
644 /**
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700645 * Returns a characteristic with id equal to instanceId.
646 * @hide
647 */
648 /*package*/ BluetoothGattCharacteristic getCharacteristicById(BluetoothDevice device, int instanceId) {
649 for(BluetoothGattService svc : mServices) {
650 for(BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700651 if (charac.getInstanceId() == instanceId)
652 return charac;
653 }
654 }
655 return null;
656 }
657
658 /**
659 * Returns a descriptor with id equal to instanceId.
660 * @hide
661 */
662 /*package*/ BluetoothGattDescriptor getDescriptorById(BluetoothDevice device, int instanceId) {
663 for(BluetoothGattService svc : mServices) {
664 for(BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
665 for(BluetoothGattDescriptor desc : charac.getDescriptors()) {
666 if (desc.getInstanceId() == instanceId)
667 return desc;
668 }
669 }
670 }
671 return null;
672 }
673
674 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800675 * Register an application callback to start using GATT.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800676 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700677 * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
Matthew Xieddf7e472013-03-01 18:41:02 -0800678 * is used to notify success or failure if the function returns true.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800679 *
680 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
681 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800682 * @param callback GATT callback handler that will receive asynchronous callbacks.
683 * @return If true, the callback will be called to notify success or failure,
684 * false on immediate error
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800685 */
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700686 private boolean registerApp(BluetoothGattCallback callback, Handler handler) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800687 if (DBG) Log.d(TAG, "registerApp()");
688 if (mService == null) return false;
689
690 mCallback = callback;
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700691 mHandler = handler;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800692 UUID uuid = UUID.randomUUID();
693 if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);
694
695 try {
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700696 mService.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800697 } catch (RemoteException e) {
698 Log.e(TAG,"",e);
699 return false;
700 }
701
702 return true;
703 }
704
705 /**
706 * Unregister the current application and callbacks.
707 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800708 private void unregisterApp() {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800709 if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf);
710 if (mService == null || mClientIf == 0) return;
711
712 try {
713 mCallback = null;
714 mService.unregisterClient(mClientIf);
715 mClientIf = 0;
716 } catch (RemoteException e) {
717 Log.e(TAG,"",e);
718 }
719 }
720
721 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800722 * Initiate a connection to a Bluetooth GATT capable device.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800723 *
724 * <p>The connection may not be established right away, but will be
725 * completed when the remote device is available. A
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700726 * {@link BluetoothGattCallback#onConnectionStateChange} callback will be
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800727 * invoked when the connection state changes as a result of this function.
728 *
Andre Eisenbach6ce4db02014-07-16 23:02:42 -0700729 * <p>The autoConnect parameter determines whether to actively connect to
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800730 * the remote device, or rather passively scan and finalize the connection
731 * when the remote device is in range/available. Generally, the first ever
732 * connection to a device should be direct (autoConnect set to false) and
733 * subsequent connections to known devices should be invoked with the
Matthew Xieddf7e472013-03-01 18:41:02 -0800734 * autoConnect parameter set to true.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800735 *
736 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
737 *
738 * @param device Remote device to connect to
739 * @param autoConnect Whether to directly connect to the remote device (false)
740 * or to automatically connect as soon as the remote
741 * device becomes available (true).
742 * @return true, if the connection attempt was initiated successfully
743 */
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700744 /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback,
745 Handler handler) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800746 if (DBG) Log.d(TAG, "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect);
747 synchronized(mStateLock) {
748 if (mConnState != CONN_STATE_IDLE) {
749 throw new IllegalStateException("Not idle");
750 }
751 mConnState = CONN_STATE_CONNECTING;
752 }
Sungki Kimd35167a2016-05-19 10:18:07 -0700753
754 mAutoConnect = autoConnect;
755
Jakub Pawlowskib0f64742017-04-21 03:49:00 -0700756 if (!registerApp(callback, handler)) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800757 synchronized(mStateLock) {
758 mConnState = CONN_STATE_IDLE;
759 }
760 Log.e(TAG, "Failed to register callback");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800761 return false;
762 }
763
Sungki Kimd35167a2016-05-19 10:18:07 -0700764 // The connection will continue in the onClientRegistered callback
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800765 return true;
766 }
767
768 /**
769 * Disconnects an established connection, or cancels a connection attempt
770 * currently in progress.
771 *
772 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800773 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800774 public void disconnect() {
775 if (DBG) Log.d(TAG, "cancelOpen() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800776 if (mService == null || mClientIf == 0) return;
777
778 try {
Matthew Xieddf7e472013-03-01 18:41:02 -0800779 mService.clientDisconnect(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800780 } catch (RemoteException e) {
781 Log.e(TAG,"",e);
782 }
Matthew Xie33ec9842013-04-03 00:29:27 -0700783 }
784
785 /**
786 * Connect back to remote device.
787 *
788 * <p>This method is used to re-connect to a remote device after the
789 * connection has been dropped. If the device is not in range, the
790 * re-connection will be triggered once the device is back in range.
791 *
792 * @return true, if the connection attempt was initiated successfully
793 */
794 public boolean connect() {
795 try {
796 mService.clientConnect(mClientIf, mDevice.getAddress(),
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800797 false, mTransport, mPhy); // autoConnect is inverse of "isDirect"
Matthew Xie33ec9842013-04-03 00:29:27 -0700798 return true;
799 } catch (RemoteException e) {
800 Log.e(TAG,"",e);
801 return false;
802 }
803 }
804
805 /**
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800806 * Set the preferred connection PHY for this app. Please note that this is just a
Jakub Pawlowskif752ace2017-03-22 22:44:09 -0700807 * recommendation, whether the PHY change will happen depends on other applications peferences,
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800808 * local and remote controller capabilities. Controller can override these settings.
809 * <p>
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700810 * {@link BluetoothGattCallback#onPhyUpdate} will be triggered as a result of this call, even
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800811 * if no PHY change happens. It is also triggered when remote device updates the PHY.
812 *
813 * @param txPhy preferred transmitter PHY. Bitwise OR of any of
Jakub Pawlowskia5151372017-04-12 08:51:22 -0700814 * {@link BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK},
815 * and {@link BluetoothDevice#PHY_LE_CODED_MASK}.
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800816 * @param rxPhy preferred receiver PHY. Bitwise OR of any of
Jakub Pawlowskia5151372017-04-12 08:51:22 -0700817 * {@link BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK},
818 * and {@link BluetoothDevice#PHY_LE_CODED_MASK}.
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800819 * @param phyOptions preferred coding to use when transmitting on the LE Coded PHY. Can be one
820 * of {@link BluetoothDevice#PHY_OPTION_NO_PREFERRED},
821 * {@link BluetoothDevice#PHY_OPTION_S2} or {@link BluetoothDevice#PHY_OPTION_S8}
822 */
823 public void setPreferredPhy(int txPhy, int rxPhy, int phyOptions) {
824 try {
825 mService.clientSetPreferredPhy(mClientIf, mDevice.getAddress(), txPhy, rxPhy,
826 phyOptions);
827 } catch (RemoteException e) {
828 Log.e(TAG,"",e);
829 }
830 }
831
832 /**
833 * Read the current transmitter PHY and receiver PHY of the connection. The values are returned
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700834 * in {@link BluetoothGattCallback#onPhyRead}
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800835 */
836 public void readPhy() {
837 try {
838 mService.clientReadPhy(mClientIf, mDevice.getAddress());
839 } catch (RemoteException e) {
840 Log.e(TAG,"",e);
841 }
842 }
843
844 /**
Matthew Xie33ec9842013-04-03 00:29:27 -0700845 * Return the remote bluetooth device this GATT client targets to
846 *
847 * @return remote bluetooth device
848 */
849 public BluetoothDevice getDevice() {
850 return mDevice;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800851 }
852
853 /**
854 * Discovers services offered by a remote device as well as their
855 * characteristics and descriptors.
856 *
857 * <p>This is an asynchronous operation. Once service discovery is completed,
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700858 * the {@link BluetoothGattCallback#onServicesDiscovered} callback is
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800859 * triggered. If the discovery was successful, the remote services can be
860 * retrieved using the {@link #getServices} function.
861 *
862 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
863 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800864 * @return true, if the remote service discovery has been started
865 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800866 public boolean discoverServices() {
867 if (DBG) Log.d(TAG, "discoverServices() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800868 if (mService == null || mClientIf == 0) return false;
869
870 mServices.clear();
871
872 try {
Matthew Xieddf7e472013-03-01 18:41:02 -0800873 mService.discoverServices(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800874 } catch (RemoteException e) {
875 Log.e(TAG,"",e);
876 return false;
877 }
878
879 return true;
880 }
881
882 /**
883 * Returns a list of GATT services offered by the remote device.
884 *
885 * <p>This function requires that service discovery has been completed
886 * for the given device.
887 *
888 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
889 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800890 * @return List of services on the remote device. Returns an empty list
891 * if service discovery has not yet been performed.
892 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800893 public List<BluetoothGattService> getServices() {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800894 List<BluetoothGattService> result =
895 new ArrayList<BluetoothGattService>();
896
897 for (BluetoothGattService service : mServices) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800898 if (service.getDevice().equals(mDevice)) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800899 result.add(service);
900 }
901 }
902
903 return result;
904 }
905
906 /**
907 * Returns a {@link BluetoothGattService}, if the requested UUID is
908 * supported by the remote device.
909 *
910 * <p>This function requires that service discovery has been completed
911 * for the given device.
912 *
913 * <p>If multiple instances of the same service (as identified by UUID)
914 * exist, the first instance of the service is returned.
915 *
916 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
917 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800918 * @param uuid UUID of the requested service
919 * @return BluetoothGattService if supported, or null if the requested
920 * service is not offered by the remote device.
921 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800922 public BluetoothGattService getService(UUID uuid) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800923 for (BluetoothGattService service : mServices) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800924 if (service.getDevice().equals(mDevice) &&
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800925 service.getUuid().equals(uuid)) {
926 return service;
927 }
928 }
929
930 return null;
931 }
932
933 /**
934 * Reads the requested characteristic from the associated remote device.
935 *
936 * <p>This is an asynchronous operation. The result of the read operation
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700937 * is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800938 * callback.
939 *
940 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
941 *
942 * @param characteristic Characteristic to read from the remote device
943 * @return true, if the read operation was initiated successfully
944 */
945 public boolean readCharacteristic(BluetoothGattCharacteristic characteristic) {
946 if ((characteristic.getProperties() &
947 BluetoothGattCharacteristic.PROPERTY_READ) == 0) return false;
948
Andre Eisenbach55d19e42014-07-18 14:38:36 -0700949 if (VDBG) Log.d(TAG, "readCharacteristic() - uuid: " + characteristic.getUuid());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800950 if (mService == null || mClientIf == 0) return false;
951
952 BluetoothGattService service = characteristic.getService();
953 if (service == null) return false;
954
955 BluetoothDevice device = service.getDevice();
956 if (device == null) return false;
957
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700958 synchronized(mDeviceBusy) {
959 if (mDeviceBusy) return false;
960 mDeviceBusy = true;
961 }
962
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800963 try {
964 mService.readCharacteristic(mClientIf, device.getAddress(),
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700965 characteristic.getInstanceId(), AUTHENTICATION_NONE);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800966 } catch (RemoteException e) {
967 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700968 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800969 return false;
970 }
971
972 return true;
973 }
974
975 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800976 * Writes a given characteristic and its values to the associated remote device.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800977 *
978 * <p>Once the write operation has been completed, the
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700979 * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800980 * reporting the result of the operation.
981 *
982 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
983 *
984 * @param characteristic Characteristic to write on the remote device
985 * @return true, if the write operation was initiated successfully
986 */
987 public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
988 if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
989 && (characteristic.getProperties() &
990 BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) return false;
991
Andre Eisenbach55d19e42014-07-18 14:38:36 -0700992 if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid());
Prerepa Viswanadhamff5e5db32014-12-04 10:12:55 -0800993 if (mService == null || mClientIf == 0 || characteristic.getValue() == null) return false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800994
995 BluetoothGattService service = characteristic.getService();
996 if (service == null) return false;
997
998 BluetoothDevice device = service.getDevice();
999 if (device == null) return false;
1000
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001001 synchronized(mDeviceBusy) {
1002 if (mDeviceBusy) return false;
1003 mDeviceBusy = true;
1004 }
1005
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001006 try {
1007 mService.writeCharacteristic(mClientIf, device.getAddress(),
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -07001008 characteristic.getInstanceId(), characteristic.getWriteType(),
1009 AUTHENTICATION_NONE, characteristic.getValue());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001010 } catch (RemoteException e) {
1011 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001012 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001013 return false;
1014 }
1015
1016 return true;
1017 }
1018
1019 /**
1020 * Reads the value for a given descriptor from the associated remote device.
1021 *
1022 * <p>Once the read operation has been completed, the
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001023 * {@link BluetoothGattCallback#onDescriptorRead} callback is
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001024 * triggered, signaling the result of the operation.
1025 *
1026 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1027 *
1028 * @param descriptor Descriptor value to read from the remote device
1029 * @return true, if the read operation was initiated successfully
1030 */
1031 public boolean readDescriptor(BluetoothGattDescriptor descriptor) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001032 if (VDBG) Log.d(TAG, "readDescriptor() - uuid: " + descriptor.getUuid());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001033 if (mService == null || mClientIf == 0) return false;
1034
1035 BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
1036 if (characteristic == null) return false;
1037
1038 BluetoothGattService service = characteristic.getService();
1039 if (service == null) return false;
1040
1041 BluetoothDevice device = service.getDevice();
1042 if (device == null) return false;
1043
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001044 synchronized(mDeviceBusy) {
1045 if (mDeviceBusy) return false;
1046 mDeviceBusy = true;
1047 }
1048
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001049 try {
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -07001050 mService.readDescriptor(mClientIf, device.getAddress(),
1051 descriptor.getInstanceId(), AUTHENTICATION_NONE);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001052 } catch (RemoteException e) {
1053 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001054 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001055 return false;
1056 }
1057
1058 return true;
1059 }
1060
1061 /**
1062 * Write the value of a given descriptor to the associated remote device.
1063 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001064 * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001065 * triggered to report the result of the write operation.
1066 *
1067 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1068 *
1069 * @param descriptor Descriptor to write to the associated remote device
1070 * @return true, if the write operation was initiated successfully
1071 */
1072 public boolean writeDescriptor(BluetoothGattDescriptor descriptor) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001073 if (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid());
Prerepa Viswanadhamff5e5db32014-12-04 10:12:55 -08001074 if (mService == null || mClientIf == 0 || descriptor.getValue() == null) return false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001075
1076 BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
1077 if (characteristic == null) return false;
1078
1079 BluetoothGattService service = characteristic.getService();
1080 if (service == null) return false;
1081
1082 BluetoothDevice device = service.getDevice();
1083 if (device == null) return false;
1084
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001085 synchronized(mDeviceBusy) {
1086 if (mDeviceBusy) return false;
1087 mDeviceBusy = true;
1088 }
1089
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001090 try {
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -07001091 mService.writeDescriptor(mClientIf, device.getAddress(), descriptor.getInstanceId(),
Jakub Pawlowski8e970d62016-03-30 22:58:17 -07001092 AUTHENTICATION_NONE, descriptor.getValue());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001093 } catch (RemoteException e) {
1094 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001095 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001096 return false;
1097 }
1098
1099 return true;
1100 }
1101
1102 /**
1103 * Initiates a reliable write transaction for a given remote device.
1104 *
1105 * <p>Once a reliable write transaction has been initiated, all calls
1106 * to {@link #writeCharacteristic} are sent to the remote device for
1107 * verification and queued up for atomic execution. The application will
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001108 * receive an {@link BluetoothGattCallback#onCharacteristicWrite} callback
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001109 * in response to every {@link #writeCharacteristic} call and is responsible
1110 * for verifying if the value has been transmitted accurately.
1111 *
1112 * <p>After all characteristics have been queued up and verified,
1113 * {@link #executeReliableWrite} will execute all writes. If a characteristic
1114 * was not written correctly, calling {@link #abortReliableWrite} will
1115 * cancel the current transaction without commiting any values on the
1116 * remote device.
1117 *
1118 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1119 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001120 * @return true, if the reliable write transaction has been initiated
1121 */
Matthew Xieddf7e472013-03-01 18:41:02 -08001122 public boolean beginReliableWrite() {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001123 if (VDBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001124 if (mService == null || mClientIf == 0) return false;
1125
1126 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001127 mService.beginReliableWrite(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001128 } catch (RemoteException e) {
1129 Log.e(TAG,"",e);
1130 return false;
1131 }
1132
1133 return true;
1134 }
1135
1136 /**
1137 * Executes a reliable write transaction for a given remote device.
1138 *
1139 * <p>This function will commit all queued up characteristic write
1140 * operations for a given remote device.
1141 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001142 * <p>A {@link BluetoothGattCallback#onReliableWriteCompleted} callback is
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001143 * invoked to indicate whether the transaction has been executed correctly.
1144 *
1145 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1146 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001147 * @return true, if the request to execute the transaction has been sent
1148 */
Matthew Xieddf7e472013-03-01 18:41:02 -08001149 public boolean executeReliableWrite() {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001150 if (VDBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001151 if (mService == null || mClientIf == 0) return false;
1152
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001153 synchronized(mDeviceBusy) {
1154 if (mDeviceBusy) return false;
1155 mDeviceBusy = true;
1156 }
1157
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001158 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001159 mService.endReliableWrite(mClientIf, mDevice.getAddress(), true);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001160 } catch (RemoteException e) {
1161 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001162 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001163 return false;
1164 }
1165
1166 return true;
1167 }
1168
1169 /**
1170 * Cancels a reliable write transaction for a given device.
1171 *
1172 * <p>Calling this function will discard all queued characteristic write
1173 * operations for a given remote device.
1174 *
1175 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001176 */
John Du48f8b5d2013-08-19 12:20:37 -07001177 public void abortReliableWrite() {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001178 if (VDBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001179 if (mService == null || mClientIf == 0) return;
1180
1181 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001182 mService.endReliableWrite(mClientIf, mDevice.getAddress(), false);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001183 } catch (RemoteException e) {
1184 Log.e(TAG,"",e);
1185 }
1186 }
1187
1188 /**
John Dub7b7d7a2013-08-20 14:03:28 -07001189 * @deprecated Use {@link #abortReliableWrite()}
John Du48f8b5d2013-08-19 12:20:37 -07001190 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07001191 @Deprecated
John Du48f8b5d2013-08-19 12:20:37 -07001192 public void abortReliableWrite(BluetoothDevice mDevice) {
1193 abortReliableWrite();
1194 }
1195
1196 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001197 * Enable or disable notifications/indications for a given characteristic.
1198 *
1199 * <p>Once notifications are enabled for a characteristic, a
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001200 * {@link BluetoothGattCallback#onCharacteristicChanged} callback will be
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001201 * triggered if the remote device indicates that the given characteristic
1202 * has changed.
1203 *
1204 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1205 *
1206 * @param characteristic The characteristic for which to enable notifications
1207 * @param enable Set to true to enable notifications/indications
1208 * @return true, if the requested notification status was set successfully
1209 */
1210 public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
1211 boolean enable) {
1212 if (DBG) Log.d(TAG, "setCharacteristicNotification() - uuid: " + characteristic.getUuid()
1213 + " enable: " + enable);
1214 if (mService == null || mClientIf == 0) return false;
1215
1216 BluetoothGattService service = characteristic.getService();
1217 if (service == null) return false;
1218
1219 BluetoothDevice device = service.getDevice();
1220 if (device == null) return false;
1221
1222 try {
1223 mService.registerForNotification(mClientIf, device.getAddress(),
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -07001224 characteristic.getInstanceId(), enable);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001225 } catch (RemoteException e) {
1226 Log.e(TAG,"",e);
1227 return false;
1228 }
1229
1230 return true;
1231 }
1232
1233 /**
1234 * Clears the internal cache and forces a refresh of the services from the
1235 * remote device.
1236 * @hide
1237 */
Matthew Xieddf7e472013-03-01 18:41:02 -08001238 public boolean refresh() {
1239 if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001240 if (mService == null || mClientIf == 0) return false;
1241
1242 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001243 mService.refreshDevice(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001244 } catch (RemoteException e) {
1245 Log.e(TAG,"",e);
1246 return false;
1247 }
1248
1249 return true;
1250 }
1251
1252 /**
1253 * Read the RSSI for a connected remote device.
1254 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001255 * <p>The {@link BluetoothGattCallback#onReadRemoteRssi} callback will be
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001256 * invoked when the RSSI value has been read.
1257 *
1258 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1259 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001260 * @return true, if the RSSI value has been requested successfully
1261 */
Matthew Xieddf7e472013-03-01 18:41:02 -08001262 public boolean readRemoteRssi() {
1263 if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001264 if (mService == null || mClientIf == 0) return false;
1265
1266 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001267 mService.readRemoteRssi(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001268 } catch (RemoteException e) {
1269 Log.e(TAG,"",e);
1270 return false;
1271 }
1272
1273 return true;
1274 }
1275
1276 /**
Andre Eisenbach4072da02014-08-19 17:58:55 -07001277 * Request an MTU size used for a given connection.
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001278 *
1279 * <p>When performing a write request operation (write without response),
1280 * the data sent is truncated to the MTU size. This function may be used
Andre Eisenbach4072da02014-08-19 17:58:55 -07001281 * to request a larger MTU size to be able to send more data at once.
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001282 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001283 * <p>A {@link BluetoothGattCallback#onMtuChanged} callback will indicate
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001284 * whether this operation was successful.
1285 *
1286 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1287 *
1288 * @return true, if the new MTU value has been requested successfully
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001289 */
Andre Eisenbach4072da02014-08-19 17:58:55 -07001290 public boolean requestMtu(int mtu) {
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001291 if (DBG) Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()
1292 + " mtu: " + mtu);
1293 if (mService == null || mClientIf == 0) return false;
1294
1295 try {
1296 mService.configureMTU(mClientIf, mDevice.getAddress(), mtu);
1297 } catch (RemoteException e) {
1298 Log.e(TAG,"",e);
1299 return false;
1300 }
1301
1302 return true;
1303 }
1304
1305 /**
Andre Eisenbach6ce4db02014-07-16 23:02:42 -07001306 * Request a connection parameter update.
1307 *
1308 * <p>This function will send a connection parameter update request to the
1309 * remote device.
1310 *
1311 * @param connectionPriority Request a specific connection priority. Must be one of
Andre Eisenbach4072da02014-08-19 17:58:55 -07001312 * {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED},
1313 * {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH}
1314 * or {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}.
Andre Eisenbach6ce4db02014-07-16 23:02:42 -07001315 * @throws IllegalArgumentException If the parameters are outside of their
1316 * specified range.
1317 */
Andre Eisenbach4072da02014-08-19 17:58:55 -07001318 public boolean requestConnectionPriority(int connectionPriority) {
1319 if (connectionPriority < CONNECTION_PRIORITY_BALANCED ||
1320 connectionPriority > CONNECTION_PRIORITY_LOW_POWER) {
Andre Eisenbach6ce4db02014-07-16 23:02:42 -07001321 throw new IllegalArgumentException("connectionPriority not within valid range");
1322 }
1323
Andre Eisenbach4072da02014-08-19 17:58:55 -07001324 if (DBG) Log.d(TAG, "requestConnectionPriority() - params: " + connectionPriority);
Andre Eisenbach6ce4db02014-07-16 23:02:42 -07001325 if (mService == null || mClientIf == 0) return false;
1326
1327 try {
1328 mService.connectionParameterUpdate(mClientIf, mDevice.getAddress(), connectionPriority);
1329 } catch (RemoteException e) {
1330 Log.e(TAG,"",e);
1331 return false;
1332 }
1333
1334 return true;
1335 }
1336
1337 /**
Matthew Xieddf7e472013-03-01 18:41:02 -08001338 * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
1339 * with {@link BluetoothProfile#GATT} as argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001340 *
Matthew Xieddf7e472013-03-01 18:41:02 -08001341 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001342 */
1343 @Override
1344 public int getConnectionState(BluetoothDevice device) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001345 throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001346 }
1347
1348 /**
Matthew Xieddf7e472013-03-01 18:41:02 -08001349 * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
1350 * with {@link BluetoothProfile#GATT} as argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001351 *
Matthew Xieddf7e472013-03-01 18:41:02 -08001352 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001353 */
1354 @Override
1355 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xieddf7e472013-03-01 18:41:02 -08001356 throw new UnsupportedOperationException
1357 ("Use BluetoothManager#getConnectedDevices instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001358 }
1359
1360 /**
Matthew Xieddf7e472013-03-01 18:41:02 -08001361 * Not supported - please use
1362 * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
1363 * with {@link BluetoothProfile#GATT} as first argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001364 *
Matthew Xieddf7e472013-03-01 18:41:02 -08001365 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001366 */
1367 @Override
1368 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001369 throw new UnsupportedOperationException
1370 ("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001371 }
1372}