diff options
Diffstat (limited to 'core/java/android/bluetooth/BluetoothGatt.java')
| -rw-r--r-- | core/java/android/bluetooth/BluetoothGatt.java | 1848 |
1 files changed, 0 insertions, 1848 deletions
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java deleted file mode 100644 index b531829d2940..000000000000 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ /dev/null @@ -1,1848 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.bluetooth; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.RequiresNoPermission; -import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.os.Build; -import android.os.Handler; -import android.os.ParcelUuid; -import android.os.RemoteException; -import android.util.Log; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Public API for the Bluetooth GATT Profile. - * - * <p>This class provides Bluetooth GATT functionality to enable communication - * with Bluetooth Smart or Smart Ready devices. - * - * <p>To connect to a remote peripheral device, create a {@link BluetoothGattCallback} - * and call {@link BluetoothDevice#connectGatt} to get a instance of this class. - * GATT capable devices can be discovered using the Bluetooth device discovery or BLE - * scan process. - */ -public final class BluetoothGatt implements BluetoothProfile { - private static final String TAG = "BluetoothGatt"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - @UnsupportedAppUsage - private IBluetoothGatt mService; - @UnsupportedAppUsage - private volatile BluetoothGattCallback mCallback; - private Handler mHandler; - @UnsupportedAppUsage - private int mClientIf; - private BluetoothDevice mDevice; - @UnsupportedAppUsage - private boolean mAutoConnect; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - private int mAuthRetryState; - private int mConnState; - private final Object mStateLock = new Object(); - private final Object mDeviceBusyLock = new Object(); - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private Boolean mDeviceBusy = false; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int mTransport; - private int mPhy; - private boolean mOpportunistic; - private final AttributionSource mAttributionSource; - - private static final int AUTH_RETRY_STATE_IDLE = 0; - private static final int AUTH_RETRY_STATE_NO_MITM = 1; - private static final int AUTH_RETRY_STATE_MITM = 2; - - private static final int CONN_STATE_IDLE = 0; - private static final int CONN_STATE_CONNECTING = 1; - private static final int CONN_STATE_CONNECTED = 2; - private static final int CONN_STATE_DISCONNECTING = 3; - private static final int CONN_STATE_CLOSED = 4; - - private static final int WRITE_CHARACTERISTIC_MAX_RETRIES = 5; - private static final int WRITE_CHARACTERISTIC_TIME_TO_WAIT = 10; // milliseconds - - private List<BluetoothGattService> mServices; - - /** A GATT operation completed successfully */ - public static final int GATT_SUCCESS = 0; - - /** GATT read operation is not permitted */ - public static final int GATT_READ_NOT_PERMITTED = 0x2; - - /** GATT write operation is not permitted */ - public static final int GATT_WRITE_NOT_PERMITTED = 0x3; - - /** Insufficient authentication for a given operation */ - public static final int GATT_INSUFFICIENT_AUTHENTICATION = 0x5; - - /** The given request is not supported */ - public static final int GATT_REQUEST_NOT_SUPPORTED = 0x6; - - /** Insufficient encryption for a given operation */ - public static final int GATT_INSUFFICIENT_ENCRYPTION = 0xf; - - /** A read or write operation was requested with an invalid offset */ - public static final int GATT_INVALID_OFFSET = 0x7; - - /** Insufficient authorization for a given operation */ - public static final int GATT_INSUFFICIENT_AUTHORIZATION = 0x8; - - /** A write operation exceeds the maximum length of the attribute */ - public static final int GATT_INVALID_ATTRIBUTE_LENGTH = 0xd; - - /** A remote device connection is congested. */ - public static final int GATT_CONNECTION_CONGESTED = 0x8f; - - /** A GATT operation failed, errors other than the above */ - public static final int GATT_FAILURE = 0x101; - - /** - * Connection parameter update - Use the connection parameters recommended by the - * Bluetooth SIG. This is the default value if no connection parameter update - * is requested. - */ - public static final int CONNECTION_PRIORITY_BALANCED = 0; - - /** - * Connection parameter update - Request a high priority, low latency connection. - * An application should only request high priority connection parameters to transfer large - * amounts of data over LE quickly. Once the transfer is complete, the application should - * request {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED} connection parameters to reduce - * energy use. - */ - public static final int CONNECTION_PRIORITY_HIGH = 1; - - /** Connection parameter update - Request low power, reduced data rate connection parameters. */ - public static final int CONNECTION_PRIORITY_LOW_POWER = 2; - - /** - * No authentication required. - * - * @hide - */ - /*package*/ static final int AUTHENTICATION_NONE = 0; - - /** - * Authentication requested; no person-in-the-middle protection required. - * - * @hide - */ - /*package*/ static final int AUTHENTICATION_NO_MITM = 1; - - /** - * Authentication with person-in-the-middle protection requested. - * - * @hide - */ - /*package*/ static final int AUTHENTICATION_MITM = 2; - - /** - * Bluetooth GATT callbacks. Overrides the default BluetoothGattCallback implementation. - */ - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final IBluetoothGattCallback mBluetoothGattCallback = - new IBluetoothGattCallback.Stub() { - /** - * Application interface registered - app is ready to go - * @hide - */ - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - public void onClientRegistered(int status, int clientIf) { - if (DBG) { - Log.d(TAG, "onClientRegistered() - status=" + status - + " clientIf=" + clientIf); - } - if (VDBG) { - synchronized (mStateLock) { - if (mConnState != CONN_STATE_CONNECTING) { - Log.e(TAG, "Bad connection state: " + mConnState); - } - } - } - mClientIf = clientIf; - if (status != GATT_SUCCESS) { - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onConnectionStateChange(BluetoothGatt.this, - GATT_FAILURE, - BluetoothProfile.STATE_DISCONNECTED); - } - } - }); - - synchronized (mStateLock) { - mConnState = CONN_STATE_IDLE; - } - return; - } - try { - mService.clientConnect(mClientIf, mDevice.getAddress(), - !mAutoConnect, mTransport, mOpportunistic, - mPhy, mAttributionSource); // autoConnect is inverse of "isDirect" - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Phy update callback - * @hide - */ - @Override - public void onPhyUpdate(String address, int txPhy, int rxPhy, int status) { - if (DBG) { - Log.d(TAG, "onPhyUpdate() - status=" + status - + " address=" + address + " txPhy=" + txPhy + " rxPhy=" + rxPhy); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status); - } - } - }); - } - - /** - * Phy read callback - * @hide - */ - @Override - public void onPhyRead(String address, int txPhy, int rxPhy, int status) { - if (DBG) { - Log.d(TAG, "onPhyRead() - status=" + status - + " address=" + address + " txPhy=" + txPhy + " rxPhy=" + rxPhy); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status); - } - } - }); - } - - /** - * Client connection state changed - * @hide - */ - @Override - public void onClientConnectionState(int status, int clientIf, - boolean connected, String address) { - if (DBG) { - Log.d(TAG, "onClientConnectionState() - status=" + status - + " clientIf=" + clientIf + " device=" + address); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - int profileState = connected ? BluetoothProfile.STATE_CONNECTED : - BluetoothProfile.STATE_DISCONNECTED; - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onConnectionStateChange(BluetoothGatt.this, status, - profileState); - } - } - }); - - synchronized (mStateLock) { - if (connected) { - mConnState = CONN_STATE_CONNECTED; - } else { - mConnState = CONN_STATE_IDLE; - } - } - - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - } - - /** - * Remote search has been completed. - * The internal object structure should now reflect the state - * of the remote device database. Let the application know that - * we are done at this point. - * @hide - */ - @Override - public void onSearchComplete(String address, List<BluetoothGattService> services, - int status) { - if (DBG) { - Log.d(TAG, - "onSearchComplete() = Device=" + address + " Status=" + status); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - - for (BluetoothGattService s : services) { - //services we receive don't have device set properly. - s.setDevice(mDevice); - } - - mServices.addAll(services); - - // Fix references to included services, as they doesn't point to right objects. - for (BluetoothGattService fixedService : mServices) { - ArrayList<BluetoothGattService> includedServices = - new ArrayList(fixedService.getIncludedServices()); - fixedService.getIncludedServices().clear(); - - for (BluetoothGattService brokenRef : includedServices) { - BluetoothGattService includedService = getService(mDevice, - brokenRef.getUuid(), brokenRef.getInstanceId()); - if (includedService != null) { - fixedService.addIncludedService(includedService); - } else { - Log.e(TAG, "Broken GATT database: can't find included service."); - } - } - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onServicesDiscovered(BluetoothGatt.this, status); - } - } - }); - } - - /** - * Remote characteristic has been read. - * Updates the internal value. - * @hide - */ - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - public void onCharacteristicRead(String address, int status, int handle, - byte[] value) { - if (VDBG) { - Log.d(TAG, "onCharacteristicRead() - Device=" + address - + " handle=" + handle + " Status=" + status); - } - - if (!address.equals(mDevice.getAddress())) { - return; - } - - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - - if ((status == GATT_INSUFFICIENT_AUTHENTICATION - || status == GATT_INSUFFICIENT_ENCRYPTION) - && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) { - try { - final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) - ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; - mService.readCharacteristic( - mClientIf, address, handle, authReq, mAttributionSource); - mAuthRetryState++; - return; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - mAuthRetryState = AUTH_RETRY_STATE_IDLE; - - BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, - handle); - if (characteristic == null) { - Log.w(TAG, "onCharacteristicRead() failed to find characteristic!"); - return; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - if (status == 0) characteristic.setValue(value); - callback.onCharacteristicRead(BluetoothGatt.this, characteristic, - value, status); - // Keep calling deprecated callback to maintain app compatibility - callback.onCharacteristicRead(BluetoothGatt.this, characteristic, - status); - } - } - }); - } - - /** - * Characteristic has been written to the remote device. - * Let the app know how we did... - * @hide - */ - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - public void onCharacteristicWrite(String address, int status, int handle, - byte[] value) { - if (VDBG) { - Log.d(TAG, "onCharacteristicWrite() - Device=" + address - + " handle=" + handle + " Status=" + status); - } - - if (!address.equals(mDevice.getAddress())) { - return; - } - - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - - BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, - handle); - if (characteristic == null) return; - - if ((status == GATT_INSUFFICIENT_AUTHENTICATION - || status == GATT_INSUFFICIENT_ENCRYPTION) - && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) { - try { - final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) - ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; - int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN; - for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) { - requestStatus = mService.writeCharacteristic(mClientIf, address, - handle, characteristic.getWriteType(), authReq, - value, mAttributionSource); - if (requestStatus - != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) { - break; - } - try { - Thread.sleep(WRITE_CHARACTERISTIC_TIME_TO_WAIT); - } catch (InterruptedException e) { - } - } - mAuthRetryState++; - return; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - mAuthRetryState = AUTH_RETRY_STATE_IDLE; - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onCharacteristicWrite(BluetoothGatt.this, characteristic, - status); - } - } - }); - } - - /** - * Remote characteristic has been updated. - * Updates the internal value. - * @hide - */ - @Override - public void onNotify(String address, int handle, byte[] value) { - if (VDBG) Log.d(TAG, "onNotify() - Device=" + address + " handle=" + handle); - - if (!address.equals(mDevice.getAddress())) { - return; - } - - BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, - handle); - if (characteristic == null) return; - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - characteristic.setValue(value); - callback.onCharacteristicChanged(BluetoothGatt.this, - characteristic, value); - // Keep calling deprecated callback to maintain app compatibility - callback.onCharacteristicChanged(BluetoothGatt.this, - characteristic); - } - } - }); - } - - /** - * Descriptor has been read. - * @hide - */ - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - public void onDescriptorRead(String address, int status, int handle, byte[] value) { - if (VDBG) { - Log.d(TAG, - "onDescriptorRead() - Device=" + address + " handle=" + handle); - } - - if (!address.equals(mDevice.getAddress())) { - return; - } - - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - - BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle); - if (descriptor == null) return; - - - if ((status == GATT_INSUFFICIENT_AUTHENTICATION - || status == GATT_INSUFFICIENT_ENCRYPTION) - && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) { - try { - final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) - ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; - mService.readDescriptor( - mClientIf, address, handle, authReq, mAttributionSource); - mAuthRetryState++; - return; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - mAuthRetryState = AUTH_RETRY_STATE_IDLE; - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - if (status == 0) descriptor.setValue(value); - callback.onDescriptorRead(BluetoothGatt.this, descriptor, status, - value); - // Keep calling deprecated callback to maintain app compatibility - callback.onDescriptorRead(BluetoothGatt.this, descriptor, status); - } - } - }); - } - - /** - * Descriptor write operation complete. - * @hide - */ - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - public void onDescriptorWrite(String address, int status, int handle, - byte[] value) { - if (VDBG) { - Log.d(TAG, - "onDescriptorWrite() - Device=" + address + " handle=" + handle); - } - - if (!address.equals(mDevice.getAddress())) { - return; - } - - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - - BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle); - if (descriptor == null) return; - - if ((status == GATT_INSUFFICIENT_AUTHENTICATION - || status == GATT_INSUFFICIENT_ENCRYPTION) - && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) { - try { - final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) - ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; - mService.writeDescriptor(mClientIf, address, handle, - authReq, value, mAttributionSource); - mAuthRetryState++; - return; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - mAuthRetryState = AUTH_RETRY_STATE_IDLE; - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onDescriptorWrite(BluetoothGatt.this, descriptor, status); - } - } - }); - } - - /** - * Prepared write transaction completed (or aborted) - * @hide - */ - @Override - public void onExecuteWrite(String address, int status) { - if (VDBG) { - Log.d(TAG, "onExecuteWrite() - Device=" + address - + " status=" + status); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onReliableWriteCompleted(BluetoothGatt.this, status); - } - } - }); - } - - /** - * Remote device RSSI has been read - * @hide - */ - @Override - public void onReadRemoteRssi(String address, int rssi, int status) { - if (VDBG) { - Log.d(TAG, "onReadRemoteRssi() - Device=" + address - + " rssi=" + rssi + " status=" + status); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onReadRemoteRssi(BluetoothGatt.this, rssi, status); - } - } - }); - } - - /** - * Callback invoked when the MTU for a given connection changes - * @hide - */ - @Override - public void onConfigureMTU(String address, int mtu, int status) { - if (DBG) { - Log.d(TAG, "onConfigureMTU() - Device=" + address - + " mtu=" + mtu + " status=" + status); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onMtuChanged(BluetoothGatt.this, mtu, status); - } - } - }); - } - - /** - * Callback invoked when the given connection is updated - * @hide - */ - @Override - public void onConnectionUpdated(String address, int interval, int latency, - int timeout, int status) { - if (DBG) { - Log.d(TAG, "onConnectionUpdated() - Device=" + address - + " interval=" + interval + " latency=" + latency - + " timeout=" + timeout + " status=" + status); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onConnectionUpdated(BluetoothGatt.this, interval, latency, - timeout, status); - } - } - }); - } - - /** - * Callback invoked when service changed event is received - * @hide - */ - @Override - public void onServiceChanged(String address) { - if (DBG) { - Log.d(TAG, "onServiceChanged() - Device=" + address); - } - - if (!address.equals(mDevice.getAddress())) { - return; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onServiceChanged(BluetoothGatt.this); - } - } - }); - } - }; - - /* package */ BluetoothGatt(IBluetoothGatt iGatt, BluetoothDevice device, int transport, - boolean opportunistic, int phy, AttributionSource attributionSource) { - mService = iGatt; - mDevice = device; - mTransport = transport; - mPhy = phy; - mOpportunistic = opportunistic; - mAttributionSource = attributionSource; - mServices = new ArrayList<BluetoothGattService>(); - - mConnState = CONN_STATE_IDLE; - mAuthRetryState = AUTH_RETRY_STATE_IDLE; - } - - /** - * Close this Bluetooth GATT client. - * - * Application should call this method as early as possible after it is done with - * this GATT client. - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void close() { - if (DBG) Log.d(TAG, "close()"); - - unregisterApp(); - mConnState = CONN_STATE_CLOSED; - mAuthRetryState = AUTH_RETRY_STATE_IDLE; - } - - /** - * Returns a service by UUID, instance and type. - * - * @hide - */ - /*package*/ BluetoothGattService getService(BluetoothDevice device, UUID uuid, - int instanceId) { - for (BluetoothGattService svc : mServices) { - if (svc.getDevice().equals(device) - && svc.getInstanceId() == instanceId - && svc.getUuid().equals(uuid)) { - return svc; - } - } - return null; - } - - - /** - * Returns a characteristic with id equal to instanceId. - * - * @hide - */ - /*package*/ BluetoothGattCharacteristic getCharacteristicById(BluetoothDevice device, - int instanceId) { - for (BluetoothGattService svc : mServices) { - for (BluetoothGattCharacteristic charac : svc.getCharacteristics()) { - if (charac.getInstanceId() == instanceId) { - return charac; - } - } - } - return null; - } - - /** - * Returns a descriptor with id equal to instanceId. - * - * @hide - */ - /*package*/ BluetoothGattDescriptor getDescriptorById(BluetoothDevice device, int instanceId) { - for (BluetoothGattService svc : mServices) { - for (BluetoothGattCharacteristic charac : svc.getCharacteristics()) { - for (BluetoothGattDescriptor desc : charac.getDescriptors()) { - if (desc.getInstanceId() == instanceId) { - return desc; - } - } - } - } - return null; - } - - /** - * Queue the runnable on a {@link Handler} provided by the user, or execute the runnable - * immediately if no Handler was provided. - */ - private void runOrQueueCallback(final Runnable cb) { - if (mHandler == null) { - try { - cb.run(); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception in callback", ex); - } - } else { - mHandler.post(cb); - } - } - - /** - * Register an application callback to start using GATT. - * - * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered} - * is used to notify success or failure if the function returns true. - * - * @param callback GATT callback handler that will receive asynchronous callbacks. - * @return If true, the callback will be called to notify success or failure, false on immediate - * error - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private boolean registerApp(BluetoothGattCallback callback, Handler handler) { - return registerApp(callback, handler, false); - } - - /** - * Register an application callback to start using GATT. - * - * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered} - * is used to notify success or failure if the function returns true. - * - * @param callback GATT callback handler that will receive asynchronous callbacks. - * @param eatt_support indicate to allow for eatt support - * @return If true, the callback will be called to notify success or failure, false on immediate - * error - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private boolean registerApp(BluetoothGattCallback callback, Handler handler, - boolean eatt_support) { - if (DBG) Log.d(TAG, "registerApp()"); - if (mService == null) return false; - - mCallback = callback; - mHandler = handler; - UUID uuid = UUID.randomUUID(); - if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid); - - try { - mService.registerClient( - new ParcelUuid(uuid), mBluetoothGattCallback, eatt_support, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Unregister the current application and callbacks. - */ - @UnsupportedAppUsage - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private void unregisterApp() { - if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf); - if (mService == null || mClientIf == 0) return; - - try { - mCallback = null; - mService.unregisterClient(mClientIf, mAttributionSource); - mClientIf = 0; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Initiate a connection to a Bluetooth GATT capable device. - * - * <p>The connection may not be established right away, but will be - * completed when the remote device is available. A - * {@link BluetoothGattCallback#onConnectionStateChange} callback will be - * invoked when the connection state changes as a result of this function. - * - * <p>The autoConnect parameter determines whether to actively connect to - * the remote device, or rather passively scan and finalize the connection - * when the remote device is in range/available. Generally, the first ever - * connection to a device should be direct (autoConnect set to false) and - * subsequent connections to known devices should be invoked with the - * autoConnect parameter set to true. - * - * @param device Remote device to connect to - * @param autoConnect Whether to directly connect to the remote device (false) or to - * automatically connect as soon as the remote device becomes available (true). - * @return true, if the connection attempt was initiated successfully - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback, - Handler handler) { - if (DBG) { - Log.d(TAG, - "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect); - } - synchronized (mStateLock) { - if (mConnState != CONN_STATE_IDLE) { - throw new IllegalStateException("Not idle"); - } - mConnState = CONN_STATE_CONNECTING; - } - - mAutoConnect = autoConnect; - - if (!registerApp(callback, handler)) { - synchronized (mStateLock) { - mConnState = CONN_STATE_IDLE; - } - Log.e(TAG, "Failed to register callback"); - return false; - } - - // The connection will continue in the onClientRegistered callback - return true; - } - - /** - * Disconnects an established connection, or cancels a connection attempt - * currently in progress. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void disconnect() { - if (DBG) Log.d(TAG, "cancelOpen() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return; - - try { - mService.clientDisconnect(mClientIf, mDevice.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Connect back to remote device. - * - * <p>This method is used to re-connect to a remote device after the - * connection has been dropped. If the device is not in range, the - * re-connection will be triggered once the device is back in range. - * - * @return true, if the connection attempt was initiated successfully - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean connect() { - try { - // autoConnect is inverse of "isDirect" - mService.clientConnect(mClientIf, mDevice.getAddress(), false, mTransport, - mOpportunistic, mPhy, mAttributionSource); - return true; - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - } - - /** - * Set the preferred connection PHY for this app. Please note that this is just a - * recommendation, whether the PHY change will happen depends on other applications preferences, - * local and remote controller capabilities. Controller can override these settings. - * <p> - * {@link BluetoothGattCallback#onPhyUpdate} will be triggered as a result of this call, even - * if no PHY change happens. It is also triggered when remote device updates the PHY. - * - * @param txPhy preferred transmitter PHY. Bitwise OR of any of {@link - * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link - * BluetoothDevice#PHY_LE_CODED_MASK}. - * @param rxPhy preferred receiver PHY. Bitwise OR of any of {@link - * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link - * BluetoothDevice#PHY_LE_CODED_MASK}. - * @param phyOptions preferred coding to use when transmitting on the LE Coded PHY. Can be one - * of {@link BluetoothDevice#PHY_OPTION_NO_PREFERRED}, {@link BluetoothDevice#PHY_OPTION_S2} or - * {@link BluetoothDevice#PHY_OPTION_S8} - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void setPreferredPhy(int txPhy, int rxPhy, int phyOptions) { - try { - mService.clientSetPreferredPhy(mClientIf, mDevice.getAddress(), txPhy, rxPhy, - phyOptions, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Read the current transmitter PHY and receiver PHY of the connection. The values are returned - * in {@link BluetoothGattCallback#onPhyRead} - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void readPhy() { - try { - mService.clientReadPhy(mClientIf, mDevice.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Return the remote bluetooth device this GATT client targets to - * - * @return remote bluetooth device - */ - @RequiresNoPermission - public BluetoothDevice getDevice() { - return mDevice; - } - - /** - * Discovers services offered by a remote device as well as their - * characteristics and descriptors. - * - * <p>This is an asynchronous operation. Once service discovery is completed, - * the {@link BluetoothGattCallback#onServicesDiscovered} callback is - * triggered. If the discovery was successful, the remote services can be - * retrieved using the {@link #getServices} function. - * - * @return true, if the remote service discovery has been started - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean discoverServices() { - if (DBG) Log.d(TAG, "discoverServices() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return false; - - mServices.clear(); - - try { - mService.discoverServices(mClientIf, mDevice.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Discovers a service by UUID. This is exposed only for passing PTS tests. - * It should never be used by real applications. The service is not searched - * for characteristics and descriptors, or returned in any callback. - * - * @return true, if the remote service discovery has been started - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean discoverServiceByUuid(UUID uuid) { - if (DBG) Log.d(TAG, "discoverServiceByUuid() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return false; - - mServices.clear(); - - try { - mService.discoverServiceByUuid( - mClientIf, mDevice.getAddress(), new ParcelUuid(uuid), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - return true; - } - - /** - * Returns a list of GATT services offered by the remote device. - * - * <p>This function requires that service discovery has been completed - * for the given device. - * - * @return List of services on the remote device. Returns an empty list if service discovery has - * not yet been performed. - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public List<BluetoothGattService> getServices() { - List<BluetoothGattService> result = - new ArrayList<BluetoothGattService>(); - - for (BluetoothGattService service : mServices) { - if (service.getDevice().equals(mDevice)) { - result.add(service); - } - } - - return result; - } - - /** - * Returns a {@link BluetoothGattService}, if the requested UUID is - * supported by the remote device. - * - * <p>This function requires that service discovery has been completed - * for the given device. - * - * <p>If multiple instances of the same service (as identified by UUID) - * exist, the first instance of the service is returned. - * - * @param uuid UUID of the requested service - * @return BluetoothGattService if supported, or null if the requested service is not offered by - * the remote device. - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public BluetoothGattService getService(UUID uuid) { - for (BluetoothGattService service : mServices) { - if (service.getDevice().equals(mDevice) && service.getUuid().equals(uuid)) { - return service; - } - } - - return null; - } - - /** - * Reads the requested characteristic from the associated remote device. - * - * <p>This is an asynchronous operation. The result of the read operation - * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt, - * BluetoothGattCharacteristic, byte[], int)} callback. - * - * @param characteristic Characteristic to read from the remote device - * @return true, if the read operation was initiated successfully - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean readCharacteristic(BluetoothGattCharacteristic characteristic) { - if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) == 0) { - return false; - } - - if (VDBG) Log.d(TAG, "readCharacteristic() - uuid: " + characteristic.getUuid()); - if (mService == null || mClientIf == 0) return false; - - BluetoothGattService service = characteristic.getService(); - if (service == null) return false; - - BluetoothDevice device = service.getDevice(); - if (device == null) return false; - - synchronized (mDeviceBusyLock) { - if (mDeviceBusy) return false; - mDeviceBusy = true; - } - - try { - mService.readCharacteristic(mClientIf, device.getAddress(), - characteristic.getInstanceId(), AUTHENTICATION_NONE, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - return false; - } - - return true; - } - - /** - * Reads the characteristic using its UUID from the associated remote device. - * - * <p>This is an asynchronous operation. The result of the read operation - * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt, - * BluetoothGattCharacteristic, byte[], int)} callback. - * - * @param uuid UUID of characteristic to read from the remote device - * @return true, if the read operation was initiated successfully - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean readUsingCharacteristicUuid(UUID uuid, int startHandle, int endHandle) { - if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid); - if (mService == null || mClientIf == 0) return false; - - synchronized (mDeviceBusyLock) { - if (mDeviceBusy) return false; - mDeviceBusy = true; - } - - try { - mService.readUsingCharacteristicUuid(mClientIf, mDevice.getAddress(), - new ParcelUuid(uuid), startHandle, endHandle, AUTHENTICATION_NONE, - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - return false; - } - - return true; - } - - - /** - * Writes a given characteristic and its values to the associated remote device. - * - * <p>Once the write operation has been completed, the - * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked, - * reporting the result of the operation. - * - * @param characteristic Characteristic to write on the remote device - * @return true, if the write operation was initiated successfully - * @throws IllegalArgumentException if characteristic or its value are null - * - * @deprecated Use {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], - * int)} as this is not memory safe. - */ - @Deprecated - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) { - try { - return writeCharacteristic(characteristic, characteristic.getValue(), - characteristic.getWriteType()) == BluetoothStatusCodes.SUCCESS; - } catch (Exception e) { - return false; - } - } - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - BluetoothStatusCodes.SUCCESS, - BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, - BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION, - BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED, - BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND, - BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED, - BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY, - BluetoothStatusCodes.ERROR_UNKNOWN - }) - public @interface WriteOperationReturnValues{} - - /** - * Writes a given characteristic and its values to the associated remote device. - * - * <p>Once the write operation has been completed, the - * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked, - * reporting the result of the operation. - * - * @param characteristic Characteristic to write on the remote device - * @return whether the characteristic was successfully written to - * @throws IllegalArgumentException if characteristic or value are null - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @WriteOperationReturnValues - public int writeCharacteristic(@NonNull BluetoothGattCharacteristic characteristic, - @NonNull byte[] value, int writeType) { - if (characteristic == null) { - throw new IllegalArgumentException("characteristic must not be null"); - } - if (value == null) { - throw new IllegalArgumentException("value must not be null"); - } - if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid()); - if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0 - && (characteristic.getProperties() - & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) { - return BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED; - } - if (mService == null || mClientIf == 0) { - return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; - } - - BluetoothGattService service = characteristic.getService(); - if (service == null) { - throw new IllegalArgumentException("Characteristic must have a non-null service"); - } - - BluetoothDevice device = service.getDevice(); - if (device == null) { - throw new IllegalArgumentException("Service must have a non-null device"); - } - - synchronized (mDeviceBusyLock) { - if (mDeviceBusy) { - return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY; - } - mDeviceBusy = true; - } - - int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN; - try { - for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) { - requestStatus = mService.writeCharacteristic(mClientIf, device.getAddress(), - characteristic.getInstanceId(), writeType, AUTHENTICATION_NONE, value, - mAttributionSource); - if (requestStatus != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) { - break; - } - try { - Thread.sleep(WRITE_CHARACTERISTIC_TIME_TO_WAIT); - } catch (InterruptedException e) { - } - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - throw e.rethrowFromSystemServer(); - } - - return requestStatus; - } - - /** - * Reads the value for a given descriptor from the associated remote device. - * - * <p>Once the read operation has been completed, the - * {@link BluetoothGattCallback#onDescriptorRead} callback is - * triggered, signaling the result of the operation. - * - * @param descriptor Descriptor value to read from the remote device - * @return true, if the read operation was initiated successfully - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean readDescriptor(BluetoothGattDescriptor descriptor) { - if (VDBG) Log.d(TAG, "readDescriptor() - uuid: " + descriptor.getUuid()); - if (mService == null || mClientIf == 0) return false; - - BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic(); - if (characteristic == null) return false; - - BluetoothGattService service = characteristic.getService(); - if (service == null) return false; - - BluetoothDevice device = service.getDevice(); - if (device == null) return false; - - synchronized (mDeviceBusyLock) { - if (mDeviceBusy) return false; - mDeviceBusy = true; - } - - try { - mService.readDescriptor(mClientIf, device.getAddress(), - descriptor.getInstanceId(), AUTHENTICATION_NONE, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - return false; - } - - return true; - } - - /** - * Write the value of a given descriptor to the associated remote device. - * - * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the - * result of the write operation. - * - * @param descriptor Descriptor to write to the associated remote device - * @return true, if the write operation was initiated successfully - * @throws IllegalArgumentException if descriptor or its value are null - * - * @deprecated Use {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])} as - * this is not memory safe. - */ - @Deprecated - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean writeDescriptor(BluetoothGattDescriptor descriptor) { - try { - return writeDescriptor(descriptor, descriptor.getValue()) - == BluetoothStatusCodes.SUCCESS; - } catch (Exception e) { - return false; - } - } - - /** - * Write the value of a given descriptor to the associated remote device. - * - * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the - * result of the write operation. - * - * @param descriptor Descriptor to write to the associated remote device - * @return true, if the write operation was initiated successfully - * @throws IllegalArgumentException if descriptor or value are null - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @WriteOperationReturnValues - public int writeDescriptor(@NonNull BluetoothGattDescriptor descriptor, - @NonNull byte[] value) { - if (descriptor == null) { - throw new IllegalArgumentException("descriptor must not be null"); - } - if (value == null) { - throw new IllegalArgumentException("value must not be null"); - } - if (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid()); - if (mService == null || mClientIf == 0) { - return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; - } - - BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic(); - if (characteristic == null) { - throw new IllegalArgumentException("Descriptor must have a non-null characteristic"); - } - - BluetoothGattService service = characteristic.getService(); - if (service == null) { - throw new IllegalArgumentException("Characteristic must have a non-null service"); - } - - BluetoothDevice device = service.getDevice(); - if (device == null) { - throw new IllegalArgumentException("Service must have a non-null device"); - } - - synchronized (mDeviceBusyLock) { - if (mDeviceBusy) return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY; - mDeviceBusy = true; - } - - try { - return mService.writeDescriptor(mClientIf, device.getAddress(), - descriptor.getInstanceId(), AUTHENTICATION_NONE, value, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - e.rethrowFromSystemServer(); - } - return BluetoothStatusCodes.ERROR_UNKNOWN; - } - - /** - * Initiates a reliable write transaction for a given remote device. - * - * <p>Once a reliable write transaction has been initiated, all calls - * to {@link #writeCharacteristic} are sent to the remote device for - * verification and queued up for atomic execution. The application will - * receive a {@link BluetoothGattCallback#onCharacteristicWrite} callback in response to every - * {@link #writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} call and is - * responsible for verifying if the value has been transmitted accurately. - * - * <p>After all characteristics have been queued up and verified, - * {@link #executeReliableWrite} will execute all writes. If a characteristic - * was not written correctly, calling {@link #abortReliableWrite} will - * cancel the current transaction without committing any values on the - * remote device. - * - * @return true, if the reliable write transaction has been initiated - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean beginReliableWrite() { - if (VDBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return false; - - try { - mService.beginReliableWrite(mClientIf, mDevice.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Executes a reliable write transaction for a given remote device. - * - * <p>This function will commit all queued up characteristic write - * operations for a given remote device. - * - * <p>A {@link BluetoothGattCallback#onReliableWriteCompleted} callback is - * invoked to indicate whether the transaction has been executed correctly. - * - * @return true, if the request to execute the transaction has been sent - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean executeReliableWrite() { - if (VDBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return false; - - synchronized (mDeviceBusyLock) { - if (mDeviceBusy) return false; - mDeviceBusy = true; - } - - try { - mService.endReliableWrite(mClientIf, mDevice.getAddress(), true, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - return false; - } - - return true; - } - - /** - * Cancels a reliable write transaction for a given device. - * - * <p>Calling this function will discard all queued characteristic write - * operations for a given remote device. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void abortReliableWrite() { - if (VDBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return; - - try { - mService.endReliableWrite(mClientIf, mDevice.getAddress(), false, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * @deprecated Use {@link #abortReliableWrite()} - */ - @Deprecated - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void abortReliableWrite(BluetoothDevice mDevice) { - abortReliableWrite(); - } - - /** - * Enable or disable notifications/indications for a given characteristic. - * - * <p>Once notifications are enabled for a characteristic, a - * {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt, - * BluetoothGattCharacteristic, byte[])} callback will be triggered if the remote device - * indicates that the given characteristic has changed. - * - * @param characteristic The characteristic for which to enable notifications - * @param enable Set to true to enable notifications/indications - * @return true, if the requested notification status was set successfully - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic, - boolean enable) { - if (DBG) { - Log.d(TAG, "setCharacteristicNotification() - uuid: " + characteristic.getUuid() - + " enable: " + enable); - } - if (mService == null || mClientIf == 0) return false; - - BluetoothGattService service = characteristic.getService(); - if (service == null) return false; - - BluetoothDevice device = service.getDevice(); - if (device == null) return false; - - try { - mService.registerForNotification(mClientIf, device.getAddress(), - characteristic.getInstanceId(), enable, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Clears the internal cache and forces a refresh of the services from the - * remote device. - * - * @hide - */ - @UnsupportedAppUsage - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean refresh() { - if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return false; - - try { - mService.refreshDevice(mClientIf, mDevice.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Read the RSSI for a connected remote device. - * - * <p>The {@link BluetoothGattCallback#onReadRemoteRssi} callback will be - * invoked when the RSSI value has been read. - * - * @return true, if the RSSI value has been requested successfully - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean readRemoteRssi() { - if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return false; - - try { - mService.readRemoteRssi(mClientIf, mDevice.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Request an MTU size used for a given connection. - * - * <p>When performing a write request operation (write without response), - * the data sent is truncated to the MTU size. This function may be used - * to request a larger MTU size to be able to send more data at once. - * - * <p>A {@link BluetoothGattCallback#onMtuChanged} callback will indicate - * whether this operation was successful. - * - * @return true, if the new MTU value has been requested successfully - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean requestMtu(int mtu) { - if (DBG) { - Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress() - + " mtu: " + mtu); - } - if (mService == null || mClientIf == 0) return false; - - try { - mService.configureMTU(mClientIf, mDevice.getAddress(), mtu, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Request a connection parameter update. - * - * <p>This function will send a connection parameter update request to the - * remote device. - * - * @param connectionPriority Request a specific connection priority. Must be one of {@link - * BluetoothGatt#CONNECTION_PRIORITY_BALANCED}, {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH} - * or {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}. - * @throws IllegalArgumentException If the parameters are outside of their specified range. - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean requestConnectionPriority(int connectionPriority) { - if (connectionPriority < CONNECTION_PRIORITY_BALANCED - || connectionPriority > CONNECTION_PRIORITY_LOW_POWER) { - throw new IllegalArgumentException("connectionPriority not within valid range"); - } - - if (DBG) Log.d(TAG, "requestConnectionPriority() - params: " + connectionPriority); - if (mService == null || mClientIf == 0) return false; - - try { - mService.connectionParameterUpdate( - mClientIf, mDevice.getAddress(), connectionPriority, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Request an LE connection parameter update. - * - * <p>This function will send an LE connection parameters update request to the remote device. - * - * @return true, if the request is send to the Bluetooth stack. - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean requestLeConnectionUpdate(int minConnectionInterval, int maxConnectionInterval, - int slaveLatency, int supervisionTimeout, - int minConnectionEventLen, int maxConnectionEventLen) { - if (DBG) { - Log.d(TAG, "requestLeConnectionUpdate() - min=(" + minConnectionInterval - + ")" + (1.25 * minConnectionInterval) - + "msec, max=(" + maxConnectionInterval + ")" - + (1.25 * maxConnectionInterval) + "msec, latency=" + slaveLatency - + ", timeout=" + supervisionTimeout + "msec" + ", min_ce=" - + minConnectionEventLen + ", max_ce=" + maxConnectionEventLen); - } - if (mService == null || mClientIf == 0) return false; - - try { - mService.leConnectionUpdate(mClientIf, mDevice.getAddress(), - minConnectionInterval, maxConnectionInterval, - slaveLatency, supervisionTimeout, - minConnectionEventLen, maxConnectionEventLen, - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * @deprecated Not supported - please use {@link BluetoothManager#getConnectedDevices(int)} - * with {@link BluetoothProfile#GATT} as argument - * @throws UnsupportedOperationException - */ - @Override - @RequiresNoPermission - @Deprecated - public int getConnectionState(BluetoothDevice device) { - throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead."); - } - - /** - * @deprecated Not supported - please use {@link BluetoothManager#getConnectedDevices(int)} - * with {@link BluetoothProfile#GATT} as argument - * - * @throws UnsupportedOperationException - */ - @Override - @RequiresNoPermission - @Deprecated - public List<BluetoothDevice> getConnectedDevices() { - throw new UnsupportedOperationException( - "Use BluetoothManager#getConnectedDevices instead."); - } - - /** - * @deprecated Not supported - please use - * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])} - * with {@link BluetoothProfile#GATT} as first argument - * - * @throws UnsupportedOperationException - */ - @Override - @RequiresNoPermission - @Deprecated - public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { - throw new UnsupportedOperationException( - "Use BluetoothManager#getDevicesMatchingConnectionStates instead."); - } -} |
