blob: e77ab2e61a07bb4a0b0ffeddf5a7f25f4875671f [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 /**
Jakub Pawlowskice21cb92017-04-14 07:21:20 -0700976 * Reads the characteristic using its UUID from the associated remote device.
977 *
978 * <p>This is an asynchronous operation. The result of the read operation
979 * is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
980 * callback.
981 *
982 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
983 *
984 * @param uuid UUID of characteristic to read from the remote device
985 * @return true, if the read operation was initiated successfully
986 * @hide
987 */
988 public boolean readUsingCharacteristicUuid(UUID uuid, int startHandle, int endHandle) {
989 if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid);
990 if (mService == null || mClientIf == 0) return false;
991
992 synchronized(mDeviceBusy) {
993 if (mDeviceBusy) return false;
994 mDeviceBusy = true;
995 }
996
997 try {
998 mService.readUsingCharacteristicUuid(mClientIf, mDevice.getAddress(),
999 new ParcelUuid(uuid), startHandle, endHandle, AUTHENTICATION_NONE);
1000 } catch (RemoteException e) {
1001 Log.e(TAG,"",e);
1002 mDeviceBusy = false;
1003 return false;
1004 }
1005
1006 return true;
1007 }
1008
1009
1010 /**
Matthew Xieddf7e472013-03-01 18:41:02 -08001011 * Writes a given characteristic and its values to the associated remote device.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001012 *
1013 * <p>Once the write operation has been completed, the
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001014 * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001015 * reporting the result of the operation.
1016 *
1017 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1018 *
1019 * @param characteristic Characteristic to write on the remote device
1020 * @return true, if the write operation was initiated successfully
1021 */
1022 public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
1023 if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
1024 && (characteristic.getProperties() &
1025 BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) return false;
1026
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001027 if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid());
Prerepa Viswanadhamff5e5db32014-12-04 10:12:55 -08001028 if (mService == null || mClientIf == 0 || characteristic.getValue() == null) return false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001029
1030 BluetoothGattService service = characteristic.getService();
1031 if (service == null) return false;
1032
1033 BluetoothDevice device = service.getDevice();
1034 if (device == null) return false;
1035
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001036 synchronized(mDeviceBusy) {
1037 if (mDeviceBusy) return false;
1038 mDeviceBusy = true;
1039 }
1040
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001041 try {
1042 mService.writeCharacteristic(mClientIf, device.getAddress(),
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -07001043 characteristic.getInstanceId(), characteristic.getWriteType(),
1044 AUTHENTICATION_NONE, characteristic.getValue());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001045 } catch (RemoteException e) {
1046 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001047 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001048 return false;
1049 }
1050
1051 return true;
1052 }
1053
1054 /**
1055 * Reads the value for a given descriptor from the associated remote device.
1056 *
1057 * <p>Once the read operation has been completed, the
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001058 * {@link BluetoothGattCallback#onDescriptorRead} callback is
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001059 * triggered, signaling the result of the operation.
1060 *
1061 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1062 *
1063 * @param descriptor Descriptor value to read from the remote device
1064 * @return true, if the read operation was initiated successfully
1065 */
1066 public boolean readDescriptor(BluetoothGattDescriptor descriptor) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001067 if (VDBG) Log.d(TAG, "readDescriptor() - uuid: " + descriptor.getUuid());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001068 if (mService == null || mClientIf == 0) return false;
1069
1070 BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
1071 if (characteristic == null) return false;
1072
1073 BluetoothGattService service = characteristic.getService();
1074 if (service == null) return false;
1075
1076 BluetoothDevice device = service.getDevice();
1077 if (device == null) return false;
1078
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001079 synchronized(mDeviceBusy) {
1080 if (mDeviceBusy) return false;
1081 mDeviceBusy = true;
1082 }
1083
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001084 try {
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -07001085 mService.readDescriptor(mClientIf, device.getAddress(),
1086 descriptor.getInstanceId(), AUTHENTICATION_NONE);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001087 } catch (RemoteException e) {
1088 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001089 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001090 return false;
1091 }
1092
1093 return true;
1094 }
1095
1096 /**
1097 * Write the value of a given descriptor to the associated remote device.
1098 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001099 * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001100 * triggered to report the result of the write operation.
1101 *
1102 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1103 *
1104 * @param descriptor Descriptor to write to the associated remote device
1105 * @return true, if the write operation was initiated successfully
1106 */
1107 public boolean writeDescriptor(BluetoothGattDescriptor descriptor) {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001108 if (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid());
Prerepa Viswanadhamff5e5db32014-12-04 10:12:55 -08001109 if (mService == null || mClientIf == 0 || descriptor.getValue() == null) return false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001110
1111 BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
1112 if (characteristic == null) return false;
1113
1114 BluetoothGattService service = characteristic.getService();
1115 if (service == null) return false;
1116
1117 BluetoothDevice device = service.getDevice();
1118 if (device == null) return false;
1119
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001120 synchronized(mDeviceBusy) {
1121 if (mDeviceBusy) return false;
1122 mDeviceBusy = true;
1123 }
1124
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001125 try {
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -07001126 mService.writeDescriptor(mClientIf, device.getAddress(), descriptor.getInstanceId(),
Jakub Pawlowski8e970d62016-03-30 22:58:17 -07001127 AUTHENTICATION_NONE, descriptor.getValue());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001128 } catch (RemoteException e) {
1129 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001130 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001131 return false;
1132 }
1133
1134 return true;
1135 }
1136
1137 /**
1138 * Initiates a reliable write transaction for a given remote device.
1139 *
1140 * <p>Once a reliable write transaction has been initiated, all calls
1141 * to {@link #writeCharacteristic} are sent to the remote device for
1142 * verification and queued up for atomic execution. The application will
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001143 * receive an {@link BluetoothGattCallback#onCharacteristicWrite} callback
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001144 * in response to every {@link #writeCharacteristic} call and is responsible
1145 * for verifying if the value has been transmitted accurately.
1146 *
1147 * <p>After all characteristics have been queued up and verified,
1148 * {@link #executeReliableWrite} will execute all writes. If a characteristic
1149 * was not written correctly, calling {@link #abortReliableWrite} will
1150 * cancel the current transaction without commiting any values on the
1151 * remote device.
1152 *
1153 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1154 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001155 * @return true, if the reliable write transaction has been initiated
1156 */
Matthew Xieddf7e472013-03-01 18:41:02 -08001157 public boolean beginReliableWrite() {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001158 if (VDBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001159 if (mService == null || mClientIf == 0) return false;
1160
1161 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001162 mService.beginReliableWrite(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001163 } catch (RemoteException e) {
1164 Log.e(TAG,"",e);
1165 return false;
1166 }
1167
1168 return true;
1169 }
1170
1171 /**
1172 * Executes a reliable write transaction for a given remote device.
1173 *
1174 * <p>This function will commit all queued up characteristic write
1175 * operations for a given remote device.
1176 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001177 * <p>A {@link BluetoothGattCallback#onReliableWriteCompleted} callback is
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001178 * invoked to indicate whether the transaction has been executed correctly.
1179 *
1180 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1181 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001182 * @return true, if the request to execute the transaction has been sent
1183 */
Matthew Xieddf7e472013-03-01 18:41:02 -08001184 public boolean executeReliableWrite() {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001185 if (VDBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001186 if (mService == null || mClientIf == 0) return false;
1187
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001188 synchronized(mDeviceBusy) {
1189 if (mDeviceBusy) return false;
1190 mDeviceBusy = true;
1191 }
1192
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001193 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001194 mService.endReliableWrite(mClientIf, mDevice.getAddress(), true);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001195 } catch (RemoteException e) {
1196 Log.e(TAG,"",e);
Andre Eisenbachcc68cc92014-03-18 14:26:51 -07001197 mDeviceBusy = false;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001198 return false;
1199 }
1200
1201 return true;
1202 }
1203
1204 /**
1205 * Cancels a reliable write transaction for a given device.
1206 *
1207 * <p>Calling this function will discard all queued characteristic write
1208 * operations for a given remote device.
1209 *
1210 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001211 */
John Du48f8b5d2013-08-19 12:20:37 -07001212 public void abortReliableWrite() {
Andre Eisenbach55d19e42014-07-18 14:38:36 -07001213 if (VDBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001214 if (mService == null || mClientIf == 0) return;
1215
1216 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001217 mService.endReliableWrite(mClientIf, mDevice.getAddress(), false);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001218 } catch (RemoteException e) {
1219 Log.e(TAG,"",e);
1220 }
1221 }
1222
1223 /**
John Dub7b7d7a2013-08-20 14:03:28 -07001224 * @deprecated Use {@link #abortReliableWrite()}
John Du48f8b5d2013-08-19 12:20:37 -07001225 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -07001226 @Deprecated
John Du48f8b5d2013-08-19 12:20:37 -07001227 public void abortReliableWrite(BluetoothDevice mDevice) {
1228 abortReliableWrite();
1229 }
1230
1231 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001232 * Enable or disable notifications/indications for a given characteristic.
1233 *
1234 * <p>Once notifications are enabled for a characteristic, a
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001235 * {@link BluetoothGattCallback#onCharacteristicChanged} callback will be
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001236 * triggered if the remote device indicates that the given characteristic
1237 * has changed.
1238 *
1239 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1240 *
1241 * @param characteristic The characteristic for which to enable notifications
1242 * @param enable Set to true to enable notifications/indications
1243 * @return true, if the requested notification status was set successfully
1244 */
1245 public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
1246 boolean enable) {
1247 if (DBG) Log.d(TAG, "setCharacteristicNotification() - uuid: " + characteristic.getUuid()
1248 + " enable: " + enable);
1249 if (mService == null || mClientIf == 0) return false;
1250
1251 BluetoothGattService service = characteristic.getService();
1252 if (service == null) return false;
1253
1254 BluetoothDevice device = service.getDevice();
1255 if (device == null) return false;
1256
1257 try {
1258 mService.registerForNotification(mClientIf, device.getAddress(),
Jakub Pawlowskic9d13c32016-03-17 16:00:16 -07001259 characteristic.getInstanceId(), enable);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001260 } catch (RemoteException e) {
1261 Log.e(TAG,"",e);
1262 return false;
1263 }
1264
1265 return true;
1266 }
1267
1268 /**
1269 * Clears the internal cache and forces a refresh of the services from the
1270 * remote device.
1271 * @hide
1272 */
Matthew Xieddf7e472013-03-01 18:41:02 -08001273 public boolean refresh() {
1274 if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001275 if (mService == null || mClientIf == 0) return false;
1276
1277 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001278 mService.refreshDevice(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001279 } catch (RemoteException e) {
1280 Log.e(TAG,"",e);
1281 return false;
1282 }
1283
1284 return true;
1285 }
1286
1287 /**
1288 * Read the RSSI for a connected remote device.
1289 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001290 * <p>The {@link BluetoothGattCallback#onReadRemoteRssi} callback will be
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001291 * invoked when the RSSI value has been read.
1292 *
1293 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1294 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001295 * @return true, if the RSSI value has been requested successfully
1296 */
Matthew Xieddf7e472013-03-01 18:41:02 -08001297 public boolean readRemoteRssi() {
1298 if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001299 if (mService == null || mClientIf == 0) return false;
1300
1301 try {
Matthew Xieddf7e472013-03-01 18:41:02 -08001302 mService.readRemoteRssi(mClientIf, mDevice.getAddress());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001303 } catch (RemoteException e) {
1304 Log.e(TAG,"",e);
1305 return false;
1306 }
1307
1308 return true;
1309 }
1310
1311 /**
Andre Eisenbach4072da02014-08-19 17:58:55 -07001312 * Request an MTU size used for a given connection.
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001313 *
1314 * <p>When performing a write request operation (write without response),
1315 * the data sent is truncated to the MTU size. This function may be used
Andre Eisenbach4072da02014-08-19 17:58:55 -07001316 * to request a larger MTU size to be able to send more data at once.
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001317 *
Jakub Pawlowskid64bb882017-03-22 11:22:18 -07001318 * <p>A {@link BluetoothGattCallback#onMtuChanged} callback will indicate
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001319 * whether this operation was successful.
1320 *
1321 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1322 *
1323 * @return true, if the new MTU value has been requested successfully
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001324 */
Andre Eisenbach4072da02014-08-19 17:58:55 -07001325 public boolean requestMtu(int mtu) {
Andre Eisenbach580b0a12014-03-25 06:31:50 -07001326 if (DBG) Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()
1327 + " mtu: " + mtu);
1328 if (mService == null || mClientIf == 0) return false;
1329
1330 try {
1331 mService.configureMTU(mClientIf, mDevice.getAddress(), mtu);
1332 } catch (RemoteException e) {
1333 Log.e(TAG,"",e);
1334 return false;
1335 }
1336
1337 return true;
1338 }
1339
1340 /**
Andre Eisenbach6ce4db02014-07-16 23:02:42 -07001341 * Request a connection parameter update.
1342 *
1343 * <p>This function will send a connection parameter update request to the
1344 * remote device.
1345 *
1346 * @param connectionPriority Request a specific connection priority. Must be one of
Andre Eisenbach4072da02014-08-19 17:58:55 -07001347 * {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED},
1348 * {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH}
1349 * or {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}.
Andre Eisenbach6ce4db02014-07-16 23:02:42 -07001350 * @throws IllegalArgumentException If the parameters are outside of their
1351 * specified range.
1352 */
Andre Eisenbach4072da02014-08-19 17:58:55 -07001353 public boolean requestConnectionPriority(int connectionPriority) {
1354 if (connectionPriority < CONNECTION_PRIORITY_BALANCED ||
1355 connectionPriority > CONNECTION_PRIORITY_LOW_POWER) {
Andre Eisenbach6ce4db02014-07-16 23:02:42 -07001356 throw new IllegalArgumentException("connectionPriority not within valid range");
1357 }
1358
Andre Eisenbach4072da02014-08-19 17:58:55 -07001359 if (DBG) Log.d(TAG, "requestConnectionPriority() - params: " + connectionPriority);
Andre Eisenbach6ce4db02014-07-16 23:02:42 -07001360 if (mService == null || mClientIf == 0) return false;
1361
1362 try {
1363 mService.connectionParameterUpdate(mClientIf, mDevice.getAddress(), connectionPriority);
1364 } catch (RemoteException e) {
1365 Log.e(TAG,"",e);
1366 return false;
1367 }
1368
1369 return true;
1370 }
1371
1372 /**
Matthew Xieddf7e472013-03-01 18:41:02 -08001373 * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
1374 * with {@link BluetoothProfile#GATT} as argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001375 *
Matthew Xieddf7e472013-03-01 18:41:02 -08001376 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001377 */
1378 @Override
1379 public int getConnectionState(BluetoothDevice device) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001380 throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001381 }
1382
1383 /**
Matthew Xieddf7e472013-03-01 18:41:02 -08001384 * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
1385 * with {@link BluetoothProfile#GATT} as argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001386 *
Matthew Xieddf7e472013-03-01 18:41:02 -08001387 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001388 */
1389 @Override
1390 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xieddf7e472013-03-01 18:41:02 -08001391 throw new UnsupportedOperationException
1392 ("Use BluetoothManager#getConnectedDevices instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001393 }
1394
1395 /**
Matthew Xieddf7e472013-03-01 18:41:02 -08001396 * Not supported - please use
1397 * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
1398 * with {@link BluetoothProfile#GATT} as first argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001399 *
Matthew Xieddf7e472013-03-01 18:41:02 -08001400 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001401 */
1402 @Override
1403 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001404 throw new UnsupportedOperationException
1405 ("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001406 }
1407}