blob: d4afcbebc3d9859d74c58824478e9b8a20c2bacb [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;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080020import android.os.ParcelUuid;
21import android.os.RemoteException;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080022import android.util.Log;
23
24import java.util.ArrayList;
25import java.util.List;
26import java.util.UUID;
27
28/**
Matthew Xieddf7e472013-03-01 18:41:02 -080029 * Public API for the Bluetooth GATT Profile.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080030 *
Matthew Xieddf7e472013-03-01 18:41:02 -080031 * <p>This class provides Bluetooth GATT functionality to enable communication
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080032 * with Bluetooth Smart or Smart Ready devices.
33 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -070034 * <p>To connect to a remote peripheral device, create a {@link BluetoothGattCallback}
Matthew Xie33ec9842013-04-03 00:29:27 -070035 * and call {@link BluetoothDevice#connectGatt} to get a instance of this class.
Matthew Xieddf7e472013-03-01 18:41:02 -080036 * GATT capable devices can be discovered using the Bluetooth device discovery or BLE
37 * scan process.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080038 */
39public final class BluetoothGatt implements BluetoothProfile {
40 private static final String TAG = "BluetoothGatt";
41 private static final boolean DBG = true;
Andre Eisenbach55d19e42014-07-18 14:38:36 -070042 private static final boolean VDBG = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080043
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080044 private IBluetoothGatt mService;
Jakub Pawlowskid64bb882017-03-22 11:22:18 -070045 private BluetoothGattCallback mCallback;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080046 private int mClientIf;
Matthew Xieddf7e472013-03-01 18:41:02 -080047 private BluetoothDevice mDevice;
48 private boolean mAutoConnect;
Jacky Cheung3854e222016-10-20 13:55:21 -070049 private int mAuthRetryState;
Matthew Xieddf7e472013-03-01 18:41:02 -080050 private int mConnState;
51 private final Object mStateLock = new Object();
Andre Eisenbachcc68cc92014-03-18 14:26:51 -070052 private Boolean mDeviceBusy = false;
Ganesh Ganapathi Battab88fa822014-04-18 10:00:40 -070053 private int mTransport;
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -080054 private int mPhy;
Matthew Xieddf7e472013-03-01 18:41:02 -080055
Jacky Cheung3854e222016-10-20 13:55:21 -070056 private static final int AUTH_RETRY_STATE_IDLE = 0;
57 private static final int AUTH_RETRY_STATE_NO_MITM = 1;
58 private static final int AUTH_RETRY_STATE_MITM = 2;
59
Matthew Xieddf7e472013-03-01 18:41:02 -080060 private static final int CONN_STATE_IDLE = 0;
61 private static final int CONN_STATE_CONNECTING = 1;
62 private static final int CONN_STATE_CONNECTED = 2;
63 private static final int CONN_STATE_DISCONNECTING = 3;
Matthew Xie33ec9842013-04-03 00:29:27 -070064 private static final int CONN_STATE_CLOSED = 4;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080065
66 private List<BluetoothGattService> mServices;
67
Matthew Xieddf7e472013-03-01 18:41:02 -080068 /** A GATT operation completed successfully */
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080069 public static final int GATT_SUCCESS = 0;
70
Matthew Xieddf7e472013-03-01 18:41:02 -080071 /** GATT read operation is not permitted */
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080072 public static final int GATT_READ_NOT_PERMITTED = 0x2;
73
Matthew Xieddf7e472013-03-01 18:41:02 -080074 /** GATT write operation is not permitted */
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080075 public static final int GATT_WRITE_NOT_PERMITTED = 0x3;
76
77 /** Insufficient authentication for a given operation */
78 public static final int GATT_INSUFFICIENT_AUTHENTICATION = 0x5;
79
80 /** The given request is not supported */
81 public static final int GATT_REQUEST_NOT_SUPPORTED = 0x6;
82
83 /** Insufficient encryption for a given operation */
84 public static final int GATT_INSUFFICIENT_ENCRYPTION = 0xf;
85
86 /** A read or write operation was requested with an invalid offset */
87 public static final int GATT_INVALID_OFFSET = 0x7;
88
89 /** A write operation exceeds the maximum length of the attribute */
90 public static final int GATT_INVALID_ATTRIBUTE_LENGTH = 0xd;
91
Andre Eisenbach45a0a1a2014-06-30 11:37:05 -070092 /** A remote device connection is congested. */
Andre Eisenbachdadefda2014-03-28 14:54:53 -070093 public static final int GATT_CONNECTION_CONGESTED = 0x8f;
94
Matthew Xie90ca8072013-05-28 21:06:50 +000095 /** A GATT operation failed, errors other than the above */
96 public static final int GATT_FAILURE = 0x101;
97
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080098 /**
Andre Eisenbach6ce4db02014-07-16 23:02:42 -070099 * Connection paramter update - Use the connection paramters recommended by the
100 * Bluetooth SIG. This is the default value if no connection parameter update
101 * is requested.
102 */
Andre Eisenbach4072da02014-08-19 17:58:55 -0700103 public static final int CONNECTION_PRIORITY_BALANCED = 0;
Andre Eisenbach6ce4db02014-07-16 23:02:42 -0700104
105 /**
106 * Connection paramter update - Request a high priority, low latency connection.
107 * An application should only request high priority connection paramters to transfer
108 * large amounts of data over LE quickly. Once the transfer is complete, the application
Andre Eisenbach4072da02014-08-19 17:58:55 -0700109 * should request {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED} connectoin parameters
Andre Eisenbach6ce4db02014-07-16 23:02:42 -0700110 * to reduce energy use.
111 */
Andre Eisenbach4072da02014-08-19 17:58:55 -0700112 public static final int CONNECTION_PRIORITY_HIGH = 1;
Andre Eisenbach6ce4db02014-07-16 23:02:42 -0700113
114 /** Connection paramter update - Request low power, reduced data rate connection parameters. */
Andre Eisenbach4072da02014-08-19 17:58:55 -0700115 public static final int CONNECTION_PRIORITY_LOW_POWER = 2;
Andre Eisenbach6ce4db02014-07-16 23:02:42 -0700116
117 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800118 * No authentication required.
119 * @hide
120 */
121 /*package*/ static final int AUTHENTICATION_NONE = 0;
122
123 /**
124 * Authentication requested; no man-in-the-middle protection required.
125 * @hide
126 */
127 /*package*/ static final int AUTHENTICATION_NO_MITM = 1;
128
129 /**
130 * Authentication with man-in-the-middle protection requested.
131 * @hide
132 */
133 /*package*/ static final int AUTHENTICATION_MITM = 2;
134
135 /**
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700136 * Bluetooth GATT callbacks. Overrides the default BluetoothGattCallback implementation.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800137 */
Jakub Pawlowskid7116be2017-03-27 12:14:40 -0700138 private final IBluetoothGattCallback mBluetoothGattCallback =
139 new IBluetoothGattCallback.Stub() {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800140 /**
141 * Application interface registered - app is ready to go
142 * @hide
143 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700144 @Override
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800145 public void onClientRegistered(int status, int clientIf) {
146 if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status
147 + " clientIf=" + clientIf);
Matthew Xieddf7e472013-03-01 18:41:02 -0800148 if (VDBG) {
149 synchronized(mStateLock) {
150 if (mConnState != CONN_STATE_CONNECTING) {
151 Log.e(TAG, "Bad connection state: " + mConnState);
152 }
153 }
154 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800155 mClientIf = clientIf;
Matthew Xieddf7e472013-03-01 18:41:02 -0800156 if (status != GATT_SUCCESS) {
Matthew Xie33ec9842013-04-03 00:29:27 -0700157 mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
Matthew Xieddf7e472013-03-01 18:41:02 -0800158 BluetoothProfile.STATE_DISCONNECTED);
159 synchronized(mStateLock) {
160 mConnState = CONN_STATE_IDLE;
161 }
162 return;
163 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800164 try {
Matthew Xieddf7e472013-03-01 18:41:02 -0800165 mService.clientConnect(mClientIf, mDevice.getAddress(),
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800166 !mAutoConnect, mTransport, mPhy); // autoConnect is inverse of "isDirect"
Matthew Xieddf7e472013-03-01 18:41:02 -0800167 } catch (RemoteException e) {
168 Log.e(TAG,"",e);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800169 }
170 }
171
172 /**
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800173 * Phy update callback
174 * @hide
175 */
176 @Override
177 public void onPhyUpdate(String address, int txPhy, int rxPhy, int status) {
178 if (DBG) Log.d(TAG, "onPhyUpdate() - status=" + status
179 + " address=" + address + " txPhy=" + txPhy + " rxPhy=" + rxPhy);
180 if (!address.equals(mDevice.getAddress())) {
181 return;
182 }
183
184 try {
185 mCallback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status);
186 } catch (Exception ex) {
187 Log.w(TAG, "Unhandled exception in callback", ex);
188 }
189 }
190
191 /**
192 * Phy read callback
193 * @hide
194 */
195 @Override
196 public void onPhyRead(String address, int txPhy, int rxPhy, int status) {
197 if (DBG) Log.d(TAG, "onPhyRead() - status=" + status
198 + " address=" + address + " txPhy=" + txPhy + " rxPhy=" + rxPhy);
199 if (!address.equals(mDevice.getAddress())) {
200 return;
201 }
202
203 try {
204 mCallback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status);
205 } catch (Exception ex) {
206 Log.w(TAG, "Unhandled exception in callback", ex);
207 }
208 }
209
210 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800211 * Client connection state changed
212 * @hide
213 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700214 @Override
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800215 public void onClientConnectionState(int status, int clientIf,
216 boolean connected, String address) {
217 if (DBG) Log.d(TAG, "onClientConnectionState() - status=" + status
218 + " clientIf=" + clientIf + " device=" + address);
Matthew Xieddf7e472013-03-01 18:41:02 -0800219 if (!address.equals(mDevice.getAddress())) {
220 return;
221 }
222 int profileState = connected ? BluetoothProfile.STATE_CONNECTED :
223 BluetoothProfile.STATE_DISCONNECTED;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800224 try {
Matthew Xie33ec9842013-04-03 00:29:27 -0700225 mCallback.onConnectionStateChange(BluetoothGatt.this, status, profileState);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800226 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700227 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800228 }
Matthew Xieddf7e472013-03-01 18:41:02 -0800229
230 synchronized(mStateLock) {
231 if (connected) {
232 mConnState = CONN_STATE_CONNECTED;
233 } else {
234 mConnState = CONN_STATE_IDLE;
235 }
236 }
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700237
238 synchronized(mDeviceBusy) {
239 mDeviceBusy = false;
240 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800241 }
242
243 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800244 * Remote search has been completed.
245 * The internal object structure should now reflect the state
246 * of the remote device database. Let the application know that
247 * we are done at this point.
248 * @hide
249 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700250 @Override
Jakub Pawlowskibf0faed2016-03-01 18:50:27 -0800251 public void onSearchComplete(String address, List<BluetoothGattService> services,
252 int status) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800253 if (DBG) Log.d(TAG, "onSearchComplete() = Device=" + address + " Status=" + status);
Matthew Xieddf7e472013-03-01 18:41:02 -0800254 if (!address.equals(mDevice.getAddress())) {
255 return;
256 }
Jakub Pawlowskibf0faed2016-03-01 18:50:27 -0800257
258 for (BluetoothGattService s : services) {
259 //services we receive don't have device set properly.
260 s.setDevice(mDevice);
261 }
262
263 mServices.addAll(services);
264
265 // Fix references to included services, as they doesn't point to right objects.
266 for (BluetoothGattService fixedService : mServices) {
267 ArrayList<BluetoothGattService> includedServices =
268 new ArrayList(fixedService.getIncludedServices());
269 fixedService.getIncludedServices().clear();
270
271 for(BluetoothGattService brokenRef : includedServices) {
272 BluetoothGattService includedService = getService(mDevice,
273 brokenRef.getUuid(), brokenRef.getInstanceId(), brokenRef.getType());
274 if (includedService != null) {
275 fixedService.addIncludedService(includedService);
276 } else {
277 Log.e(TAG, "Broken GATT database: can't find included service.");
278 }
279 }
280 }
281
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800282 try {
Matthew Xie33ec9842013-04-03 00:29:27 -0700283 mCallback.onServicesDiscovered(BluetoothGatt.this, status);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800284 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700285 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800286 }
287 }
288
289 /**
290 * Remote characteristic has been read.
291 * Updates the internal value.
292 * @hide
293 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700294 @Override
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700295 public void onCharacteristicRead(String address, int status, int handle, byte[] value) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -0700296 if (VDBG) Log.d(TAG, "onCharacteristicRead() - Device=" + address
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700297 + " handle=" + handle + " Status=" + status);
298
Matthew Xieddf7e472013-03-01 18:41:02 -0800299 if (!address.equals(mDevice.getAddress())) {
300 return;
301 }
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700302
303 synchronized(mDeviceBusy) {
304 mDeviceBusy = false;
305 }
306
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800307 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
308 || status == GATT_INSUFFICIENT_ENCRYPTION)
Jacky Cheung3854e222016-10-20 13:55:21 -0700309 && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800310 try {
Jacky Cheung3854e222016-10-20 13:55:21 -0700311 final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) ?
312 AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
313 mService.readCharacteristic(mClientIf, address, handle, authReq);
314 mAuthRetryState++;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800315 return;
316 } catch (RemoteException e) {
317 Log.e(TAG,"",e);
318 }
319 }
320
Jacky Cheung3854e222016-10-20 13:55:21 -0700321 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800322
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700323 BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle);
324 if (characteristic == null) {
325 Log.w(TAG, "onCharacteristicRead() failed to find characteristic!");
326 return;
327 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800328
329 if (status == 0) characteristic.setValue(value);
330
331 try {
Matthew Xie33ec9842013-04-03 00:29:27 -0700332 mCallback.onCharacteristicRead(BluetoothGatt.this, characteristic, status);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800333 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700334 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800335 }
336 }
337
338 /**
339 * Characteristic has been written to the remote device.
340 * Let the app know how we did...
341 * @hide
342 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700343 @Override
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700344 public void onCharacteristicWrite(String address, int status, int handle) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -0700345 if (VDBG) Log.d(TAG, "onCharacteristicWrite() - Device=" + address
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700346 + " handle=" + handle + " Status=" + status);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800347
Matthew Xieddf7e472013-03-01 18:41:02 -0800348 if (!address.equals(mDevice.getAddress())) {
349 return;
350 }
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700351
352 synchronized(mDeviceBusy) {
353 mDeviceBusy = false;
354 }
355
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700356 BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800357 if (characteristic == null) return;
358
359 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
360 || status == GATT_INSUFFICIENT_ENCRYPTION)
Jacky Cheung3854e222016-10-20 13:55:21 -0700361 && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800362 try {
Jacky Cheung3854e222016-10-20 13:55:21 -0700363 final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) ?
364 AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700365 mService.writeCharacteristic(mClientIf, address, handle,
Jacky Cheung3854e222016-10-20 13:55:21 -0700366 characteristic.getWriteType(), authReq, characteristic.getValue());
367 mAuthRetryState++;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800368 return;
369 } catch (RemoteException e) {
370 Log.e(TAG,"",e);
371 }
372 }
373
Jacky Cheung3854e222016-10-20 13:55:21 -0700374 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800375
376 try {
Matthew Xie33ec9842013-04-03 00:29:27 -0700377 mCallback.onCharacteristicWrite(BluetoothGatt.this, characteristic, status);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800378 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700379 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800380 }
381 }
382
383 /**
384 * Remote characteristic has been updated.
385 * Updates the internal value.
386 * @hide
387 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700388 @Override
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700389 public void onNotify(String address, int handle, byte[] value) {
390 if (VDBG) Log.d(TAG, "onNotify() - Device=" + address + " handle=" + handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800391
Matthew Xieddf7e472013-03-01 18:41:02 -0800392 if (!address.equals(mDevice.getAddress())) {
393 return;
394 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800395
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700396 BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800397 if (characteristic == null) return;
398
399 characteristic.setValue(value);
400
401 try {
Matthew Xie33ec9842013-04-03 00:29:27 -0700402 mCallback.onCharacteristicChanged(BluetoothGatt.this, characteristic);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800403 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700404 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800405 }
406 }
407
408 /**
409 * Descriptor has been read.
410 * @hide
411 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700412 @Override
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700413 public void onDescriptorRead(String address, int status, int handle, byte[] value) {
414 if (VDBG) Log.d(TAG, "onDescriptorRead() - Device=" + address + " handle=" + handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800415
Matthew Xieddf7e472013-03-01 18:41:02 -0800416 if (!address.equals(mDevice.getAddress())) {
417 return;
418 }
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700419
420 synchronized(mDeviceBusy) {
421 mDeviceBusy = false;
422 }
423
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700424 BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800425 if (descriptor == null) return;
426
427 if (status == 0) descriptor.setValue(value);
428
429 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
430 || status == GATT_INSUFFICIENT_ENCRYPTION)
Jacky Cheung3854e222016-10-20 13:55:21 -0700431 && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800432 try {
Jacky Cheung3854e222016-10-20 13:55:21 -0700433 final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) ?
434 AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
435 mService.readDescriptor(mClientIf, address, handle, authReq);
436 mAuthRetryState++;
Andre Eisenbachd65e8f42014-07-25 15:16:11 -0700437 return;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800438 } catch (RemoteException e) {
439 Log.e(TAG,"",e);
440 }
441 }
442
Jacky Cheung3854e222016-10-20 13:55:21 -0700443 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800444
445 try {
Matthew Xie33ec9842013-04-03 00:29:27 -0700446 mCallback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800447 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700448 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800449 }
450 }
451
452 /**
453 * Descriptor write operation complete.
454 * @hide
455 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700456 @Override
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700457 public void onDescriptorWrite(String address, int status, int handle) {
458 if (VDBG) Log.d(TAG, "onDescriptorWrite() - Device=" + address + " handle=" + handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800459
Matthew Xieddf7e472013-03-01 18:41:02 -0800460 if (!address.equals(mDevice.getAddress())) {
461 return;
462 }
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700463
464 synchronized(mDeviceBusy) {
465 mDeviceBusy = false;
466 }
467
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700468 BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800469 if (descriptor == null) return;
470
471 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
472 || status == GATT_INSUFFICIENT_ENCRYPTION)
Jacky Cheung3854e222016-10-20 13:55:21 -0700473 && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800474 try {
Jacky Cheung3854e222016-10-20 13:55:21 -0700475 final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) ?
476 AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700477 mService.writeDescriptor(mClientIf, address, handle,
Jacky Cheung3854e222016-10-20 13:55:21 -0700478 authReq, descriptor.getValue());
479 mAuthRetryState++;
Andre Eisenbachd65e8f42014-07-25 15:16:11 -0700480 return;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800481 } catch (RemoteException e) {
482 Log.e(TAG,"",e);
483 }
484 }
485
Jacky Cheung3854e222016-10-20 13:55:21 -0700486 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800487
488 try {
Matthew Xie33ec9842013-04-03 00:29:27 -0700489 mCallback.onDescriptorWrite(BluetoothGatt.this, descriptor, status);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800490 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700491 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800492 }
493 }
494
495 /**
496 * Prepared write transaction completed (or aborted)
497 * @hide
498 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700499 @Override
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800500 public void onExecuteWrite(String address, int status) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -0700501 if (VDBG) Log.d(TAG, "onExecuteWrite() - Device=" + address
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800502 + " status=" + status);
Matthew Xieddf7e472013-03-01 18:41:02 -0800503 if (!address.equals(mDevice.getAddress())) {
504 return;
505 }
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700506
507 synchronized(mDeviceBusy) {
508 mDeviceBusy = false;
509 }
510
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800511 try {
Matthew Xie33ec9842013-04-03 00:29:27 -0700512 mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800513 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700514 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800515 }
516 }
517
518 /**
519 * Remote device RSSI has been read
520 * @hide
521 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700522 @Override
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800523 public void onReadRemoteRssi(String address, int rssi, int status) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -0700524 if (VDBG) Log.d(TAG, "onReadRemoteRssi() - Device=" + address +
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800525 " rssi=" + rssi + " status=" + status);
Matthew Xieddf7e472013-03-01 18:41:02 -0800526 if (!address.equals(mDevice.getAddress())) {
527 return;
528 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800529 try {
Matthew Xie33ec9842013-04-03 00:29:27 -0700530 mCallback.onReadRemoteRssi(BluetoothGatt.this, rssi, status);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800531 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700532 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800533 }
534 }
Wei Wangf3055892014-03-11 22:22:41 -0700535
536 /**
Andre Eisenbach580b0a12014-03-25 06:31:50 -0700537 * Callback invoked when the MTU for a given connection changes
538 * @hide
539 */
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700540 @Override
Andre Eisenbach580b0a12014-03-25 06:31:50 -0700541 public void onConfigureMTU(String address, int mtu, int status) {
542 if (DBG) Log.d(TAG, "onConfigureMTU() - Device=" + address +
543 " mtu=" + mtu + " status=" + status);
544 if (!address.equals(mDevice.getAddress())) {
545 return;
546 }
547 try {
Andre Eisenbach4072da02014-08-19 17:58:55 -0700548 mCallback.onMtuChanged(BluetoothGatt.this, mtu, status);
Andre Eisenbach580b0a12014-03-25 06:31:50 -0700549 } catch (Exception ex) {
550 Log.w(TAG, "Unhandled exception in callback", ex);
551 }
Wei Wangf3055892014-03-11 22:22:41 -0700552 }
Jakub Pawlowski326f7b32017-03-23 19:05:55 -0700553
554 /**
555 * Callback invoked when the given connection is updated
556 * @hide
557 */
558 @Override
559 public void onConnectionUpdated(String address, int interval, int latency,
560 int timeout, int status) {
561 if (DBG) Log.d(TAG, "onConnectionUpdated() - Device=" + address +
562 " interval=" + interval + " latency=" + latency +
563 " timeout=" + timeout + " status=" + status);
564 if (!address.equals(mDevice.getAddress())) {
565 return;
566 }
567 try {
568 mCallback.onConnectionUpdated(BluetoothGatt.this, interval, latency,
569 timeout, status);
570 } catch (Exception ex) {
571 Log.w(TAG, "Unhandled exception in callback", ex);
572 }
573 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800574 };
575
Jeremy Kleinadc26ec2016-09-27 14:34:33 -0700576 /*package*/ BluetoothGatt(IBluetoothGatt iGatt, BluetoothDevice device,
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800577 int transport, int phy) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800578 mService = iGatt;
579 mDevice = device;
Ganesh Ganapathi Battab88fa822014-04-18 10:00:40 -0700580 mTransport = transport;
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800581 mPhy = phy;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800582 mServices = new ArrayList<BluetoothGattService>();
583
Matthew Xieddf7e472013-03-01 18:41:02 -0800584 mConnState = CONN_STATE_IDLE;
Jacky Cheung3854e222016-10-20 13:55:21 -0700585 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800586 }
587
588 /**
Matthew Xie33ec9842013-04-03 00:29:27 -0700589 * Close this Bluetooth GATT client.
Matthew Xieb30f91e2013-05-29 10:19:06 -0700590 *
591 * Application should call this method as early as possible after it is done with
592 * this GATT client.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800593 */
Matthew Xie33ec9842013-04-03 00:29:27 -0700594 public void close() {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800595 if (DBG) Log.d(TAG, "close()");
596
597 unregisterApp();
Matthew Xie33ec9842013-04-03 00:29:27 -0700598 mConnState = CONN_STATE_CLOSED;
Jacky Cheung3854e222016-10-20 13:55:21 -0700599 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800600 }
601
602 /**
603 * Returns a service by UUID, instance and type.
604 * @hide
605 */
606 /*package*/ BluetoothGattService getService(BluetoothDevice device, UUID uuid,
607 int instanceId, int type) {
608 for(BluetoothGattService svc : mServices) {
609 if (svc.getDevice().equals(device) &&
610 svc.getType() == type &&
611 svc.getInstanceId() == instanceId &&
612 svc.getUuid().equals(uuid)) {
613 return svc;
614 }
615 }
616 return null;
617 }
618
619
620 /**
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700621 * Returns a characteristic with id equal to instanceId.
622 * @hide
623 */
624 /*package*/ BluetoothGattCharacteristic getCharacteristicById(BluetoothDevice device, int instanceId) {
625 for(BluetoothGattService svc : mServices) {
626 for(BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700627 if (charac.getInstanceId() == instanceId)
628 return charac;
629 }
630 }
631 return null;
632 }
633
634 /**
635 * Returns a descriptor with id equal to instanceId.
636 * @hide
637 */
638 /*package*/ BluetoothGattDescriptor getDescriptorById(BluetoothDevice device, int instanceId) {
639 for(BluetoothGattService svc : mServices) {
640 for(BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
641 for(BluetoothGattDescriptor desc : charac.getDescriptors()) {
642 if (desc.getInstanceId() == instanceId)
643 return desc;
644 }
645 }
646 }
647 return null;
648 }
649
650 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800651 * Register an application callback to start using GATT.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800652 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700653 * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
Matthew Xieddf7e472013-03-01 18:41:02 -0800654 * is used to notify success or failure if the function returns true.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800655 *
656 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
657 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800658 * @param callback GATT callback handler that will receive asynchronous callbacks.
659 * @return If true, the callback will be called to notify success or failure,
660 * false on immediate error
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800661 */
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700662 private boolean registerApp(BluetoothGattCallback callback) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800663 if (DBG) Log.d(TAG, "registerApp()");
664 if (mService == null) return false;
665
666 mCallback = callback;
667 UUID uuid = UUID.randomUUID();
668 if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);
669
670 try {
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700671 mService.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800672 } catch (RemoteException e) {
673 Log.e(TAG,"",e);
674 return false;
675 }
676
677 return true;
678 }
679
680 /**
681 * Unregister the current application and callbacks.
682 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800683 private void unregisterApp() {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800684 if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf);
685 if (mService == null || mClientIf == 0) return;
686
687 try {
688 mCallback = null;
689 mService.unregisterClient(mClientIf);
690 mClientIf = 0;
691 } catch (RemoteException e) {
692 Log.e(TAG,"",e);
693 }
694 }
695
696 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800697 * Initiate a connection to a Bluetooth GATT capable device.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800698 *
699 * <p>The connection may not be established right away, but will be
700 * completed when the remote device is available. A
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700701 * {@link BluetoothGattCallback#onConnectionStateChange} callback will be
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800702 * invoked when the connection state changes as a result of this function.
703 *
Andre Eisenbach6ce4db02014-07-16 23:02:42 -0700704 * <p>The autoConnect parameter determines whether to actively connect to
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800705 * the remote device, or rather passively scan and finalize the connection
706 * when the remote device is in range/available. Generally, the first ever
707 * connection to a device should be direct (autoConnect set to false) and
708 * subsequent connections to known devices should be invoked with the
Matthew Xieddf7e472013-03-01 18:41:02 -0800709 * autoConnect parameter set to true.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800710 *
711 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
712 *
713 * @param device Remote device to connect to
714 * @param autoConnect Whether to directly connect to the remote device (false)
715 * or to automatically connect as soon as the remote
716 * device becomes available (true).
717 * @return true, if the connection attempt was initiated successfully
718 */
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700719 /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800720 if (DBG) Log.d(TAG, "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect);
721 synchronized(mStateLock) {
722 if (mConnState != CONN_STATE_IDLE) {
723 throw new IllegalStateException("Not idle");
724 }
725 mConnState = CONN_STATE_CONNECTING;
726 }
Sungki Kimd35167a2016-05-19 10:18:07 -0700727
728 mAutoConnect = autoConnect;
729
Matthew Xieddf7e472013-03-01 18:41:02 -0800730 if (!registerApp(callback)) {
731 synchronized(mStateLock) {
732 mConnState = CONN_STATE_IDLE;
733 }
734 Log.e(TAG, "Failed to register callback");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800735 return false;
736 }
737
Sungki Kimd35167a2016-05-19 10:18:07 -0700738 // The connection will continue in the onClientRegistered callback
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800739 return true;
740 }
741
742 /**
743 * Disconnects an established connection, or cancels a connection attempt
744 * currently in progress.
745 *
746 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800747 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800748 public void disconnect() {
749 if (DBG) Log.d(TAG, "cancelOpen() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800750 if (mService == null || mClientIf == 0) return;
751
752 try {
Matthew Xieddf7e472013-03-01 18:41:02 -0800753 mService.clientDisconnect(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800754 } catch (RemoteException e) {
755 Log.e(TAG,"",e);
756 }
Matthew Xie33ec9842013-04-03 00:29:27 -0700757 }
758
759 /**
760 * Connect back to remote device.
761 *
762 * <p>This method is used to re-connect to a remote device after the
763 * connection has been dropped. If the device is not in range, the
764 * re-connection will be triggered once the device is back in range.
765 *
766 * @return true, if the connection attempt was initiated successfully
767 */
768 public boolean connect() {
769 try {
770 mService.clientConnect(mClientIf, mDevice.getAddress(),
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800771 false, mTransport, mPhy); // autoConnect is inverse of "isDirect"
Matthew Xie33ec9842013-04-03 00:29:27 -0700772 return true;
773 } catch (RemoteException e) {
774 Log.e(TAG,"",e);
775 return false;
776 }
777 }
778
779 /**
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800780 * Set the preferred connection PHY for this app. Please note that this is just a
Jakub Pawlowski08ed9242017-03-22 22:44:09 -0700781 * recommendation, whether the PHY change will happen depends on other applications peferences,
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800782 * local and remote controller capabilities. Controller can override these settings.
783 * <p>
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700784 * {@link BluetoothGattCallback#onPhyUpdate} will be triggered as a result of this call, even
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800785 * if no PHY change happens. It is also triggered when remote device updates the PHY.
786 *
787 * @param txPhy preferred transmitter PHY. Bitwise OR of any of
Jakub Pawlowski9e377192017-04-12 08:51:22 -0700788 * {@link BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK},
789 * and {@link BluetoothDevice#PHY_LE_CODED_MASK}.
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800790 * @param rxPhy preferred receiver PHY. Bitwise OR of any of
Jakub Pawlowski9e377192017-04-12 08:51:22 -0700791 * {@link BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK},
792 * and {@link BluetoothDevice#PHY_LE_CODED_MASK}.
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800793 * @param phyOptions preferred coding to use when transmitting on the LE Coded PHY. Can be one
794 * of {@link BluetoothDevice#PHY_OPTION_NO_PREFERRED},
795 * {@link BluetoothDevice#PHY_OPTION_S2} or {@link BluetoothDevice#PHY_OPTION_S8}
796 */
797 public void setPreferredPhy(int txPhy, int rxPhy, int phyOptions) {
798 try {
799 mService.clientSetPreferredPhy(mClientIf, mDevice.getAddress(), txPhy, rxPhy,
800 phyOptions);
801 } catch (RemoteException e) {
802 Log.e(TAG,"",e);
803 }
804 }
805
806 /**
807 * Read the current transmitter PHY and receiver PHY of the connection. The values are returned
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700808 * in {@link BluetoothGattCallback#onPhyRead}
Jakub Pawlowskidb5a87d2017-02-02 08:07:12 -0800809 */
810 public void readPhy() {
811 try {
812 mService.clientReadPhy(mClientIf, mDevice.getAddress());
813 } catch (RemoteException e) {
814 Log.e(TAG,"",e);
815 }
816 }
817
818 /**
Matthew Xie33ec9842013-04-03 00:29:27 -0700819 * Return the remote bluetooth device this GATT client targets to
820 *
821 * @return remote bluetooth device
822 */
823 public BluetoothDevice getDevice() {
824 return mDevice;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800825 }
826
827 /**
828 * Discovers services offered by a remote device as well as their
829 * characteristics and descriptors.
830 *
831 * <p>This is an asynchronous operation. Once service discovery is completed,
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700832 * the {@link BluetoothGattCallback#onServicesDiscovered} callback is
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800833 * triggered. If the discovery was successful, the remote services can be
834 * retrieved using the {@link #getServices} function.
835 *
836 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
837 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800838 * @return true, if the remote service discovery has been started
839 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800840 public boolean discoverServices() {
841 if (DBG) Log.d(TAG, "discoverServices() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800842 if (mService == null || mClientIf == 0) return false;
843
844 mServices.clear();
845
846 try {
Matthew Xieddf7e472013-03-01 18:41:02 -0800847 mService.discoverServices(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800848 } catch (RemoteException e) {
849 Log.e(TAG,"",e);
850 return false;
851 }
852
853 return true;
854 }
855
856 /**
857 * Returns a list of GATT services offered by the remote device.
858 *
859 * <p>This function requires that service discovery has been completed
860 * for the given device.
861 *
862 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
863 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800864 * @return List of services on the remote device. Returns an empty list
865 * if service discovery has not yet been performed.
866 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800867 public List<BluetoothGattService> getServices() {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800868 List<BluetoothGattService> result =
869 new ArrayList<BluetoothGattService>();
870
871 for (BluetoothGattService service : mServices) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800872 if (service.getDevice().equals(mDevice)) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800873 result.add(service);
874 }
875 }
876
877 return result;
878 }
879
880 /**
881 * Returns a {@link BluetoothGattService}, if the requested UUID is
882 * supported by the remote device.
883 *
884 * <p>This function requires that service discovery has been completed
885 * for the given device.
886 *
887 * <p>If multiple instances of the same service (as identified by UUID)
888 * exist, the first instance of the service is returned.
889 *
890 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
891 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800892 * @param uuid UUID of the requested service
893 * @return BluetoothGattService if supported, or null if the requested
894 * service is not offered by the remote device.
895 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800896 public BluetoothGattService getService(UUID uuid) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800897 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 service.getUuid().equals(uuid)) {
900 return service;
901 }
902 }
903
904 return null;
905 }
906
907 /**
908 * Reads the requested characteristic from the associated remote device.
909 *
910 * <p>This is an asynchronous operation. The result of the read operation
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700911 * is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800912 * callback.
913 *
914 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
915 *
916 * @param characteristic Characteristic to read from the remote device
917 * @return true, if the read operation was initiated successfully
918 */
919 public boolean readCharacteristic(BluetoothGattCharacteristic characteristic) {
920 if ((characteristic.getProperties() &
921 BluetoothGattCharacteristic.PROPERTY_READ) == 0) return false;
922
Andre Eisenbach55d19e42014-07-18 14:38:36 -0700923 if (VDBG) Log.d(TAG, "readCharacteristic() - uuid: " + characteristic.getUuid());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800924 if (mService == null || mClientIf == 0) return false;
925
926 BluetoothGattService service = characteristic.getService();
927 if (service == null) return false;
928
929 BluetoothDevice device = service.getDevice();
930 if (device == null) return false;
931
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700932 synchronized(mDeviceBusy) {
933 if (mDeviceBusy) return false;
934 mDeviceBusy = true;
935 }
936
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800937 try {
938 mService.readCharacteristic(mClientIf, device.getAddress(),
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -0700939 characteristic.getInstanceId(), AUTHENTICATION_NONE);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800940 } catch (RemoteException e) {
941 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -0700942 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800943 return false;
944 }
945
946 return true;
947 }
948
949 /**
Jakub Pawlowskide748912017-04-14 07:21:20 -0700950 * Reads the characteristic using its UUID from the associated remote device.
951 *
952 * <p>This is an asynchronous operation. The result of the read operation
953 * is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
954 * callback.
955 *
956 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
957 *
958 * @param uuid UUID of characteristic to read from the remote device
959 * @return true, if the read operation was initiated successfully
960 * @hide
961 */
962 public boolean readUsingCharacteristicUuid(UUID uuid, int startHandle, int endHandle) {
963 if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid);
964 if (mService == null || mClientIf == 0) return false;
965
966 synchronized(mDeviceBusy) {
967 if (mDeviceBusy) return false;
968 mDeviceBusy = true;
969 }
970
971 try {
972 mService.readUsingCharacteristicUuid(mClientIf, mDevice.getAddress(),
973 new ParcelUuid(uuid), startHandle, endHandle, AUTHENTICATION_NONE);
974 } catch (RemoteException e) {
975 Log.e(TAG,"",e);
976 mDeviceBusy = false;
977 return false;
978 }
979
980 return true;
981 }
982
983
984 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800985 * Writes a given characteristic and its values to the associated remote device.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800986 *
987 * <p>Once the write operation has been completed, the
Jakub Pawlowskid64bb882017-03-22 11:22:18 -0700988 * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800989 * reporting the result of the operation.
990 *
991 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
992 *
993 * @param characteristic Characteristic to write on the remote device
994 * @return true, if the write operation was initiated successfully
995 */
996 public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
997 if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
998 && (characteristic.getProperties() &
999 BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) return false;
1000
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001001 if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid());
Prerepa Viswanadhamff5e5db32014-12-04 10:12:55 -08001002 if (mService == null || mClientIf == 0 || characteristic.getValue() == null) return false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001003
1004 BluetoothGattService service = characteristic.getService();
1005 if (service == null) return false;
1006
1007 BluetoothDevice device = service.getDevice();
1008 if (device == null) return false;
1009
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001010 synchronized(mDeviceBusy) {
1011 if (mDeviceBusy) return false;
1012 mDeviceBusy = true;
1013 }
1014
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001015 try {
1016 mService.writeCharacteristic(mClientIf, device.getAddress(),
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -07001017 characteristic.getInstanceId(), characteristic.getWriteType(),
1018 AUTHENTICATION_NONE, characteristic.getValue());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001019 } catch (RemoteException e) {
1020 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001021 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001022 return false;
1023 }
1024
1025 return true;
1026 }
1027
1028 /**
1029 * Reads the value for a given descriptor from the associated remote device.
1030 *
1031 * <p>Once the read operation has been completed, the
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001032 * {@link BluetoothGattCallback#onDescriptorRead} callback is
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001033 * triggered, signaling the result of the operation.
1034 *
1035 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1036 *
1037 * @param descriptor Descriptor value to read from the remote device
1038 * @return true, if the read operation was initiated successfully
1039 */
1040 public boolean readDescriptor(BluetoothGattDescriptor descriptor) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001041 if (VDBG) Log.d(TAG, "readDescriptor() - uuid: " + descriptor.getUuid());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001042 if (mService == null || mClientIf == 0) return false;
1043
1044 BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
1045 if (characteristic == null) return false;
1046
1047 BluetoothGattService service = characteristic.getService();
1048 if (service == null) return false;
1049
1050 BluetoothDevice device = service.getDevice();
1051 if (device == null) return false;
1052
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001053 synchronized(mDeviceBusy) {
1054 if (mDeviceBusy) return false;
1055 mDeviceBusy = true;
1056 }
1057
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001058 try {
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -07001059 mService.readDescriptor(mClientIf, device.getAddress(),
1060 descriptor.getInstanceId(), AUTHENTICATION_NONE);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001061 } catch (RemoteException e) {
1062 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001063 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001064 return false;
1065 }
1066
1067 return true;
1068 }
1069
1070 /**
1071 * Write the value of a given descriptor to the associated remote device.
1072 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001073 * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001074 * triggered to report the result of the write operation.
1075 *
1076 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1077 *
1078 * @param descriptor Descriptor to write to the associated remote device
1079 * @return true, if the write operation was initiated successfully
1080 */
1081 public boolean writeDescriptor(BluetoothGattDescriptor descriptor) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001082 if (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid());
Prerepa Viswanadhamff5e5db32014-12-04 10:12:55 -08001083 if (mService == null || mClientIf == 0 || descriptor.getValue() == null) return false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001084
1085 BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
1086 if (characteristic == null) return false;
1087
1088 BluetoothGattService service = characteristic.getService();
1089 if (service == null) return false;
1090
1091 BluetoothDevice device = service.getDevice();
1092 if (device == null) return false;
1093
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001094 synchronized(mDeviceBusy) {
1095 if (mDeviceBusy) return false;
1096 mDeviceBusy = true;
1097 }
1098
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001099 try {
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -07001100 mService.writeDescriptor(mClientIf, device.getAddress(), descriptor.getInstanceId(),
Jakub Pawlowski8e970d62016-03-30 22:58:17 -07001101 AUTHENTICATION_NONE, descriptor.getValue());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001102 } catch (RemoteException e) {
1103 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001104 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001105 return false;
1106 }
1107
1108 return true;
1109 }
1110
1111 /**
1112 * Initiates a reliable write transaction for a given remote device.
1113 *
1114 * <p>Once a reliable write transaction has been initiated, all calls
1115 * to {@link #writeCharacteristic} are sent to the remote device for
1116 * verification and queued up for atomic execution. The application will
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001117 * receive an {@link BluetoothGattCallback#onCharacteristicWrite} callback
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001118 * in response to every {@link #writeCharacteristic} call and is responsible
1119 * for verifying if the value has been transmitted accurately.
1120 *
1121 * <p>After all characteristics have been queued up and verified,
1122 * {@link #executeReliableWrite} will execute all writes. If a characteristic
1123 * was not written correctly, calling {@link #abortReliableWrite} will
1124 * cancel the current transaction without commiting any values on the
1125 * remote device.
1126 *
1127 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1128 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001129 * @return true, if the reliable write transaction has been initiated
1130 */
Matthew Xieddf7e472013-03-01 18:41:02 -08001131 public boolean beginReliableWrite() {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001132 if (VDBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001133 if (mService == null || mClientIf == 0) return false;
1134
1135 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001136 mService.beginReliableWrite(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001137 } catch (RemoteException e) {
1138 Log.e(TAG,"",e);
1139 return false;
1140 }
1141
1142 return true;
1143 }
1144
1145 /**
1146 * Executes a reliable write transaction for a given remote device.
1147 *
1148 * <p>This function will commit all queued up characteristic write
1149 * operations for a given remote device.
1150 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001151 * <p>A {@link BluetoothGattCallback#onReliableWriteCompleted} callback is
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001152 * invoked to indicate whether the transaction has been executed correctly.
1153 *
1154 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1155 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001156 * @return true, if the request to execute the transaction has been sent
1157 */
Matthew Xieddf7e472013-03-01 18:41:02 -08001158 public boolean executeReliableWrite() {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001159 if (VDBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001160 if (mService == null || mClientIf == 0) return false;
1161
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001162 synchronized(mDeviceBusy) {
1163 if (mDeviceBusy) return false;
1164 mDeviceBusy = true;
1165 }
1166
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001167 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001168 mService.endReliableWrite(mClientIf, mDevice.getAddress(), true);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001169 } catch (RemoteException e) {
1170 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001171 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001172 return false;
1173 }
1174
1175 return true;
1176 }
1177
1178 /**
1179 * Cancels a reliable write transaction for a given device.
1180 *
1181 * <p>Calling this function will discard all queued characteristic write
1182 * operations for a given remote device.
1183 *
1184 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001185 */
John Du48f8b5d2013-08-19 12:20:37 -07001186 public void abortReliableWrite() {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001187 if (VDBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001188 if (mService == null || mClientIf == 0) return;
1189
1190 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001191 mService.endReliableWrite(mClientIf, mDevice.getAddress(), false);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001192 } catch (RemoteException e) {
1193 Log.e(TAG,"",e);
1194 }
1195 }
1196
1197 /**
John Dub7b7d7a2013-08-20 14:03:28 -07001198 * @deprecated Use {@link #abortReliableWrite()}
John Du48f8b5d2013-08-19 12:20:37 -07001199 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07001200 @Deprecated
John Du48f8b5d2013-08-19 12:20:37 -07001201 public void abortReliableWrite(BluetoothDevice mDevice) {
1202 abortReliableWrite();
1203 }
1204
1205 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001206 * Enable or disable notifications/indications for a given characteristic.
1207 *
1208 * <p>Once notifications are enabled for a characteristic, a
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001209 * {@link BluetoothGattCallback#onCharacteristicChanged} callback will be
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001210 * triggered if the remote device indicates that the given characteristic
1211 * has changed.
1212 *
1213 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1214 *
1215 * @param characteristic The characteristic for which to enable notifications
1216 * @param enable Set to true to enable notifications/indications
1217 * @return true, if the requested notification status was set successfully
1218 */
1219 public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
1220 boolean enable) {
1221 if (DBG) Log.d(TAG, "setCharacteristicNotification() - uuid: " + characteristic.getUuid()
1222 + " enable: " + enable);
1223 if (mService == null || mClientIf == 0) return false;
1224
1225 BluetoothGattService service = characteristic.getService();
1226 if (service == null) return false;
1227
1228 BluetoothDevice device = service.getDevice();
1229 if (device == null) return false;
1230
1231 try {
1232 mService.registerForNotification(mClientIf, device.getAddress(),
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -07001233 characteristic.getInstanceId(), enable);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001234 } catch (RemoteException e) {
1235 Log.e(TAG,"",e);
1236 return false;
1237 }
1238
1239 return true;
1240 }
1241
1242 /**
1243 * Clears the internal cache and forces a refresh of the services from the
1244 * remote device.
1245 * @hide
1246 */
Matthew Xieddf7e472013-03-01 18:41:02 -08001247 public boolean refresh() {
1248 if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001249 if (mService == null || mClientIf == 0) return false;
1250
1251 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001252 mService.refreshDevice(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001253 } catch (RemoteException e) {
1254 Log.e(TAG,"",e);
1255 return false;
1256 }
1257
1258 return true;
1259 }
1260
1261 /**
1262 * Read the RSSI for a connected remote device.
1263 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001264 * <p>The {@link BluetoothGattCallback#onReadRemoteRssi} callback will be
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001265 * invoked when the RSSI value has been read.
1266 *
1267 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1268 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001269 * @return true, if the RSSI value has been requested successfully
1270 */
Matthew Xieddf7e472013-03-01 18:41:02 -08001271 public boolean readRemoteRssi() {
1272 if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001273 if (mService == null || mClientIf == 0) return false;
1274
1275 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001276 mService.readRemoteRssi(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001277 } catch (RemoteException e) {
1278 Log.e(TAG,"",e);
1279 return false;
1280 }
1281
1282 return true;
1283 }
1284
1285 /**
Andre Eisenbach4072da02014-08-19 17:58:55 -07001286 * Request an MTU size used for a given connection.
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001287 *
1288 * <p>When performing a write request operation (write without response),
1289 * the data sent is truncated to the MTU size. This function may be used
Andre Eisenbach4072da02014-08-19 17:58:55 -07001290 * to request a larger MTU size to be able to send more data at once.
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001291 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001292 * <p>A {@link BluetoothGattCallback#onMtuChanged} callback will indicate
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001293 * whether this operation was successful.
1294 *
1295 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1296 *
1297 * @return true, if the new MTU value has been requested successfully
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001298 */
Andre Eisenbach4072da02014-08-19 17:58:55 -07001299 public boolean requestMtu(int mtu) {
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001300 if (DBG) Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()
1301 + " mtu: " + mtu);
1302 if (mService == null || mClientIf == 0) return false;
1303
1304 try {
1305 mService.configureMTU(mClientIf, mDevice.getAddress(), mtu);
1306 } catch (RemoteException e) {
1307 Log.e(TAG,"",e);
1308 return false;
1309 }
1310
1311 return true;
1312 }
1313
1314 /**
Andre Eisenbach6ce4db02014-07-16 23:02:42 -07001315 * Request a connection parameter update.
1316 *
1317 * <p>This function will send a connection parameter update request to the
1318 * remote device.
1319 *
1320 * @param connectionPriority Request a specific connection priority. Must be one of
Andre Eisenbach4072da02014-08-19 17:58:55 -07001321 * {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED},
1322 * {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH}
1323 * or {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}.
Andre Eisenbach6ce4db02014-07-16 23:02:42 -07001324 * @throws IllegalArgumentException If the parameters are outside of their
1325 * specified range.
1326 */
Andre Eisenbach4072da02014-08-19 17:58:55 -07001327 public boolean requestConnectionPriority(int connectionPriority) {
1328 if (connectionPriority < CONNECTION_PRIORITY_BALANCED ||
1329 connectionPriority > CONNECTION_PRIORITY_LOW_POWER) {
Andre Eisenbach6ce4db02014-07-16 23:02:42 -07001330 throw new IllegalArgumentException("connectionPriority not within valid range");
1331 }
1332
Andre Eisenbach4072da02014-08-19 17:58:55 -07001333 if (DBG) Log.d(TAG, "requestConnectionPriority() - params: " + connectionPriority);
Andre Eisenbach6ce4db02014-07-16 23:02:42 -07001334 if (mService == null || mClientIf == 0) return false;
1335
1336 try {
1337 mService.connectionParameterUpdate(mClientIf, mDevice.getAddress(), connectionPriority);
1338 } catch (RemoteException e) {
1339 Log.e(TAG,"",e);
1340 return false;
1341 }
1342
1343 return true;
1344 }
1345
1346 /**
Matthew Xieddf7e472013-03-01 18:41:02 -08001347 * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
1348 * with {@link BluetoothProfile#GATT} as argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001349 *
Matthew Xieddf7e472013-03-01 18:41:02 -08001350 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001351 */
1352 @Override
1353 public int getConnectionState(BluetoothDevice device) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001354 throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001355 }
1356
1357 /**
Matthew Xieddf7e472013-03-01 18:41:02 -08001358 * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
1359 * with {@link BluetoothProfile#GATT} as argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001360 *
Matthew Xieddf7e472013-03-01 18:41:02 -08001361 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001362 */
1363 @Override
1364 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xieddf7e472013-03-01 18:41:02 -08001365 throw new UnsupportedOperationException
1366 ("Use BluetoothManager#getConnectedDevices instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001367 }
1368
1369 /**
Matthew Xieddf7e472013-03-01 18:41:02 -08001370 * Not supported - please use
1371 * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
1372 * with {@link BluetoothProfile#GATT} as first argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001373 *
Matthew Xieddf7e472013-03-01 18:41:02 -08001374 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001375 */
1376 @Override
1377 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001378 throw new UnsupportedOperationException
1379 ("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001380 }
1381}