Merge "Deprecate GATT callbacks and methods that were not memory safe and replace with memory safe versions." am: eb806924d6

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1858070

Change-Id: I37032a518f4310d16ad19279265b91ab610bed18
This commit is contained in:
Rahul Sabnis
2021-11-05 05:28:28 +00:00
committed by Automerger Merge Worker
6 changed files with 310 additions and 96 deletions

View File

@@ -9125,8 +9125,10 @@ package android.bluetooth {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean requestMtu(int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean requestMtu(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setPreferredPhy(int, int, int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setPreferredPhy(int, int, int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic); method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int writeCharacteristic(@NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[], int);
method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int writeDescriptor(@NonNull android.bluetooth.BluetoothGattDescriptor, @NonNull byte[]);
field public static final int CONNECTION_PRIORITY_BALANCED = 0; // 0x0 field public static final int CONNECTION_PRIORITY_BALANCED = 0; // 0x0
field public static final int CONNECTION_PRIORITY_HIGH = 1; // 0x1 field public static final int CONNECTION_PRIORITY_HIGH = 1; // 0x1
field public static final int CONNECTION_PRIORITY_LOW_POWER = 2; // 0x2 field public static final int CONNECTION_PRIORITY_LOW_POWER = 2; // 0x2
@@ -9145,11 +9147,14 @@ package android.bluetooth {
public abstract class BluetoothGattCallback { public abstract class BluetoothGattCallback {
ctor public BluetoothGattCallback(); ctor public BluetoothGattCallback();
method public void onCharacteristicChanged(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic); method @Deprecated public void onCharacteristicChanged(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic);
method public void onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int); method public void onCharacteristicChanged(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[]);
method @Deprecated public void onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int);
method public void onCharacteristicRead(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[], int);
method public void onCharacteristicWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int); method public void onCharacteristicWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int);
method public void onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int); method public void onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int);
method public void onDescriptorRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int); method @Deprecated public void onDescriptorRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int);
method public void onDescriptorRead(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattDescriptor, int, @NonNull byte[]);
method public void onDescriptorWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int); method public void onDescriptorWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int);
method public void onMtuChanged(android.bluetooth.BluetoothGatt, int, int); method public void onMtuChanged(android.bluetooth.BluetoothGatt, int, int);
method public void onPhyRead(android.bluetooth.BluetoothGatt, int, int, int); method public void onPhyRead(android.bluetooth.BluetoothGatt, int, int, int);
@@ -9166,20 +9171,20 @@ package android.bluetooth {
method public int describeContents(); method public int describeContents();
method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID); method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors(); method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
method public Float getFloatValue(int, int); method @Deprecated public Float getFloatValue(int, int);
method public int getInstanceId(); method public int getInstanceId();
method public Integer getIntValue(int, int); method @Deprecated public Integer getIntValue(int, int);
method public int getPermissions(); method public int getPermissions();
method public int getProperties(); method public int getProperties();
method public android.bluetooth.BluetoothGattService getService(); method public android.bluetooth.BluetoothGattService getService();
method public String getStringValue(int); method @Deprecated public String getStringValue(int);
method public java.util.UUID getUuid(); method public java.util.UUID getUuid();
method public byte[] getValue(); method @Deprecated public byte[] getValue();
method public int getWriteType(); method public int getWriteType();
method public boolean setValue(byte[]); method @Deprecated public boolean setValue(byte[]);
method public boolean setValue(int, int, int); method @Deprecated public boolean setValue(int, int, int);
method public boolean setValue(int, int, int, int); method @Deprecated public boolean setValue(int, int, int, int);
method public boolean setValue(String); method @Deprecated public boolean setValue(String);
method public void setWriteType(int); method public void setWriteType(int);
method public void writeToParcel(android.os.Parcel, int); method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR; field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR;
@@ -9219,8 +9224,8 @@ package android.bluetooth {
method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(); method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic();
method public int getPermissions(); method public int getPermissions();
method public java.util.UUID getUuid(); method public java.util.UUID getUuid();
method public byte[] getValue(); method @Deprecated public byte[] getValue();
method public boolean setValue(byte[]); method @Deprecated public boolean setValue(byte[]);
method public void writeToParcel(android.os.Parcel, int); method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattDescriptor> CREATOR; field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattDescriptor> CREATOR;
field public static final byte[] DISABLE_NOTIFICATION_VALUE; field public static final byte[] DISABLE_NOTIFICATION_VALUE;
@@ -9508,8 +9513,12 @@ package android.bluetooth {
field public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; // 0x2 field public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; // 0x2
field public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; // 0x1 field public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; // 0x1
field public static final int ERROR_DEVICE_NOT_BONDED = 3; // 0x3 field public static final int ERROR_DEVICE_NOT_BONDED = 3; // 0x3
field public static final int ERROR_FEATURE_NOT_SUPPORTED = 8; // 0x8 field public static final int ERROR_FEATURE_NOT_SUPPORTED = 10; // 0xa
field public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101; // 0x65
field public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102; // 0x66
field public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; // 0x6 field public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; // 0x6
field public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; // 0x8
field public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; // 0x9
field public static final int ERROR_UNKNOWN = 2147483647; // 0x7fffffff field public static final int ERROR_UNKNOWN = 2147483647; // 0x7fffffff
field public static final int SUCCESS = 0; // 0x0 field public static final int SUCCESS = 0; // 0x0
} }

View File

@@ -16,6 +16,8 @@
package android.bluetooth; package android.bluetooth;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresNoPermission; import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission; import android.annotation.RequiresPermission;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
@@ -29,6 +31,8 @@ import android.os.ParcelUuid;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@@ -139,27 +143,6 @@ public final class BluetoothGatt implements BluetoothProfile {
/** Connection parameter update - Request low power, reduced data rate connection parameters. */ /** Connection parameter update - Request low power, reduced data rate connection parameters. */
public static final int CONNECTION_PRIORITY_LOW_POWER = 2; public static final int CONNECTION_PRIORITY_LOW_POWER = 2;
/**
* A GATT writeCharacteristic request is started successfully.
*
* @hide
*/
public static final int GATT_WRITE_REQUEST_SUCCESS = 0;
/**
* A GATT writeCharacteristic request failed to start.
*
* @hide
*/
public static final int GATT_WRITE_REQUEST_FAIL = 1;
/**
* A GATT writeCharacteristic request is issued to a busy remote device.
*
* @hide
*/
public static final int GATT_WRITE_REQUEST_BUSY = 2;
/** /**
* No authentication required. * No authentication required.
* *
@@ -429,6 +412,9 @@ public final class BluetoothGatt implements BluetoothProfile {
final BluetoothGattCallback callback = mCallback; final BluetoothGattCallback callback = mCallback;
if (callback != null) { if (callback != null) {
if (status == 0) characteristic.setValue(value); 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, callback.onCharacteristicRead(BluetoothGatt.this, characteristic,
status); status);
} }
@@ -443,7 +429,8 @@ public final class BluetoothGatt implements BluetoothProfile {
*/ */
@Override @Override
@SuppressLint("AndroidFrameworkRequiresPermission") @SuppressLint("AndroidFrameworkRequiresPermission")
public void onCharacteristicWrite(String address, int status, int handle) { public void onCharacteristicWrite(String address, int status, int handle,
byte[] value) {
if (VDBG) { if (VDBG) {
Log.d(TAG, "onCharacteristicWrite() - Device=" + address Log.d(TAG, "onCharacteristicWrite() - Device=" + address
+ " handle=" + handle + " Status=" + status); + " handle=" + handle + " Status=" + status);
@@ -467,12 +454,13 @@ public final class BluetoothGatt implements BluetoothProfile {
try { try {
final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE)
? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
int requestStatus = GATT_WRITE_REQUEST_FAIL; int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN;
for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) { for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) {
requestStatus = mService.writeCharacteristic(mClientIf, address, requestStatus = mService.writeCharacteristic(mClientIf, address,
handle, characteristic.getWriteType(), authReq, handle, characteristic.getWriteType(), authReq,
characteristic.getValue(), mAttributionSource); value, mAttributionSource);
if (requestStatus != GATT_WRITE_REQUEST_BUSY) { if (requestStatus
!= BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) {
break; break;
} }
try { try {
@@ -488,7 +476,6 @@ public final class BluetoothGatt implements BluetoothProfile {
} }
mAuthRetryState = AUTH_RETRY_STATE_IDLE; mAuthRetryState = AUTH_RETRY_STATE_IDLE;
runOrQueueCallback(new Runnable() { runOrQueueCallback(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -524,6 +511,9 @@ public final class BluetoothGatt implements BluetoothProfile {
final BluetoothGattCallback callback = mCallback; final BluetoothGattCallback callback = mCallback;
if (callback != null) { if (callback != null) {
characteristic.setValue(value); characteristic.setValue(value);
callback.onCharacteristicChanged(BluetoothGatt.this,
characteristic, value);
// Keep calling deprecated callback to maintain app compatibility
callback.onCharacteristicChanged(BluetoothGatt.this, callback.onCharacteristicChanged(BluetoothGatt.this,
characteristic); characteristic);
} }
@@ -578,6 +568,9 @@ public final class BluetoothGatt implements BluetoothProfile {
final BluetoothGattCallback callback = mCallback; final BluetoothGattCallback callback = mCallback;
if (callback != null) { if (callback != null) {
if (status == 0) descriptor.setValue(value); 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); callback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
} }
} }
@@ -590,7 +583,8 @@ public final class BluetoothGatt implements BluetoothProfile {
*/ */
@Override @Override
@SuppressLint("AndroidFrameworkRequiresPermission") @SuppressLint("AndroidFrameworkRequiresPermission")
public void onDescriptorWrite(String address, int status, int handle) { public void onDescriptorWrite(String address, int status, int handle,
byte[] value) {
if (VDBG) { if (VDBG) {
Log.d(TAG, Log.d(TAG,
"onDescriptorWrite() - Device=" + address + " handle=" + handle); "onDescriptorWrite() - Device=" + address + " handle=" + handle);
@@ -614,7 +608,7 @@ public final class BluetoothGatt implements BluetoothProfile {
final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE)
? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
mService.writeDescriptor(mClientIf, address, handle, mService.writeDescriptor(mClientIf, address, handle,
authReq, descriptor.getValue(), mAttributionSource); authReq, value, mAttributionSource);
mAuthRetryState++; mAuthRetryState++;
return; return;
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -1194,8 +1188,8 @@ public final class BluetoothGatt implements BluetoothProfile {
* Reads the requested characteristic from the associated remote device. * Reads the requested characteristic from the associated remote device.
* *
* <p>This is an asynchronous operation. The result of the read operation * <p>This is an asynchronous operation. The result of the read operation
* is reported by the {@link BluetoothGattCallback#onCharacteristicRead} * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt,
* callback. * BluetoothGattCharacteristic, byte[], int)} callback.
* *
* @param characteristic Characteristic to read from the remote device * @param characteristic Characteristic to read from the remote device
* @return true, if the read operation was initiated successfully * @return true, if the read operation was initiated successfully
@@ -1240,8 +1234,8 @@ public final class BluetoothGatt implements BluetoothProfile {
* Reads the characteristic using its UUID from the associated remote device. * Reads the characteristic using its UUID from the associated remote device.
* *
* <p>This is an asynchronous operation. The result of the read operation * <p>This is an asynchronous operation. The result of the read operation
* is reported by the {@link BluetoothGattCallback#onCharacteristicRead} * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt,
* callback. * BluetoothGattCharacteristic, byte[], int)} callback.
* *
* @param uuid UUID of characteristic to read from the remote device * @param uuid UUID of characteristic to read from the remote device
* @return true, if the read operation was initiated successfully * @return true, if the read operation was initiated successfully
@@ -1284,40 +1278,94 @@ public final class BluetoothGatt implements BluetoothProfile {
* *
* @param characteristic Characteristic to write on the remote device * @param characteristic Characteristic to write on the remote device
* @return true, if the write operation was initiated successfully * @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 @RequiresLegacyBluetoothPermission
@RequiresBluetoothConnectPermission @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) { 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 if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
&& (characteristic.getProperties() && (characteristic.getProperties()
& BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) { & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) {
return false; return BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED;
}
if (mService == null || mClientIf == 0) {
return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
} }
if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid());
if (mService == null || mClientIf == 0 || characteristic.getValue() == null) return false;
BluetoothGattService service = characteristic.getService(); BluetoothGattService service = characteristic.getService();
if (service == null) return false; if (service == null) {
throw new IllegalArgumentException("Characteristic must have a non-null service");
}
BluetoothDevice device = service.getDevice(); BluetoothDevice device = service.getDevice();
if (device == null) return false; if (device == null) {
throw new IllegalArgumentException("Service must have a non-null device");
}
synchronized (mDeviceBusyLock) { synchronized (mDeviceBusyLock) {
if (mDeviceBusy) { if (mDeviceBusy) {
return false; return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY;
} }
mDeviceBusy = true; mDeviceBusy = true;
} }
int requestStatus = GATT_WRITE_REQUEST_FAIL; int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN;
try { try {
for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) { for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) {
requestStatus = mService.writeCharacteristic(mClientIf, device.getAddress(), requestStatus = mService.writeCharacteristic(mClientIf, device.getAddress(),
characteristic.getInstanceId(), characteristic.getWriteType(), characteristic.getInstanceId(), writeType, AUTHENTICATION_NONE, value,
AUTHENTICATION_NONE, characteristic.getValue(), mAttributionSource); mAttributionSource);
if (requestStatus != GATT_WRITE_REQUEST_BUSY) { if (requestStatus != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) {
break; break;
} }
try { try {
@@ -1330,10 +1378,10 @@ public final class BluetoothGatt implements BluetoothProfile {
synchronized (mDeviceBusyLock) { synchronized (mDeviceBusyLock) {
mDeviceBusy = false; mDeviceBusy = false;
} }
return false; throw e.rethrowFromSystemServer();
} }
return requestStatus == GATT_WRITE_REQUEST_SUCCESS; return requestStatus;
} }
/** /**
@@ -1384,45 +1432,86 @@ public final class BluetoothGatt implements BluetoothProfile {
/** /**
* Write the value of a given descriptor to the associated remote device. * Write the value of a given descriptor to the associated remote device.
* *
* <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the
* triggered to report the result of the write operation. * result of the write operation.
* *
* @param descriptor Descriptor to write to the associated remote device * @param descriptor Descriptor to write to the associated remote device
* @return true, if the write operation was initiated successfully * @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 @RequiresLegacyBluetoothPermission
@RequiresBluetoothConnectPermission @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean writeDescriptor(BluetoothGattDescriptor descriptor) { 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 (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid());
if (mService == null || mClientIf == 0 || descriptor.getValue() == null) return false; if (mService == null || mClientIf == 0) {
return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
}
BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic(); BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
if (characteristic == null) return false; if (characteristic == null) {
throw new IllegalArgumentException("Descriptor must have a non-null characteristic");
}
BluetoothGattService service = characteristic.getService(); BluetoothGattService service = characteristic.getService();
if (service == null) return false; if (service == null) {
throw new IllegalArgumentException("Characteristic must have a non-null service");
}
BluetoothDevice device = service.getDevice(); BluetoothDevice device = service.getDevice();
if (device == null) return false; if (device == null) {
throw new IllegalArgumentException("Service must have a non-null device");
}
synchronized (mDeviceBusyLock) { synchronized (mDeviceBusyLock) {
if (mDeviceBusy) return false; if (mDeviceBusy) return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY;
mDeviceBusy = true; mDeviceBusy = true;
} }
try { try {
mService.writeDescriptor(mClientIf, device.getAddress(), descriptor.getInstanceId(), return mService.writeDescriptor(mClientIf, device.getAddress(),
AUTHENTICATION_NONE, descriptor.getValue(), mAttributionSource); descriptor.getInstanceId(), AUTHENTICATION_NONE, value, mAttributionSource);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "", e); Log.e(TAG, "", e);
synchronized (mDeviceBusyLock) { synchronized (mDeviceBusyLock) {
mDeviceBusy = false; mDeviceBusy = false;
} }
return false; e.rethrowFromSystemServer();
} }
return BluetoothStatusCodes.ERROR_UNKNOWN;
return true;
} }
/** /**
@@ -1431,9 +1520,9 @@ public final class BluetoothGatt implements BluetoothProfile {
* <p>Once a reliable write transaction has been initiated, all calls * <p>Once a reliable write transaction has been initiated, all calls
* to {@link #writeCharacteristic} are sent to the remote device for * to {@link #writeCharacteristic} are sent to the remote device for
* verification and queued up for atomic execution. The application will * verification and queued up for atomic execution. The application will
* receive an {@link BluetoothGattCallback#onCharacteristicWrite} callback * receive a {@link BluetoothGattCallback#onCharacteristicWrite} callback in response to every
* in response to every {@link #writeCharacteristic} call and is responsible * {@link #writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} call and is
* for verifying if the value has been transmitted accurately. * responsible for verifying if the value has been transmitted accurately.
* *
* <p>After all characteristics have been queued up and verified, * <p>After all characteristics have been queued up and verified,
* {@link #executeReliableWrite} will execute all writes. If a characteristic * {@link #executeReliableWrite} will execute all writes. If a characteristic
@@ -1530,9 +1619,9 @@ public final class BluetoothGatt implements BluetoothProfile {
* Enable or disable notifications/indications for a given characteristic. * Enable or disable notifications/indications for a given characteristic.
* *
* <p>Once notifications are enabled for a characteristic, a * <p>Once notifications are enabled for a characteristic, a
* {@link BluetoothGattCallback#onCharacteristicChanged} callback will be * {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt,
* triggered if the remote device indicates that the given characteristic * BluetoothGattCharacteristic, byte[])} callback will be triggered if the remote device
* has changed. * indicates that the given characteristic has changed.
* *
* @param characteristic The characteristic for which to enable notifications * @param characteristic The characteristic for which to enable notifications
* @param enable Set to true to enable notifications/indications * @param enable Set to true to enable notifications/indications

View File

@@ -80,15 +80,33 @@ public abstract class BluetoothGattCallback {
/** /**
* Callback reporting the result of a characteristic read operation. * Callback reporting the result of a characteristic read operation.
* *
* @param gatt GATT client invoked {@link BluetoothGatt#readCharacteristic} * @param gatt GATT client invoked
* {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)}
* @param characteristic Characteristic that was read from the associated remote device. * @param characteristic Characteristic that was read from the associated remote device.
* @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
* successfully. * successfully.
* @deprecated Use {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt,
* BluetoothGattCharacteristic, byte[], int)} as it is memory safe
*/ */
@Deprecated
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
int status) { int status) {
} }
/**
* Callback reporting the result of a characteristic read operation.
*
* @param gatt GATT client invoked
* {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)}
* @param characteristic Characteristic that was read from the associated remote device.
* @param value the value of the characteristic
* @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
* successfully.
*/
public void onCharacteristicRead(@NonNull BluetoothGatt gatt, @NonNull
BluetoothGattCharacteristic characteristic, @NonNull byte[] value, int status) {
}
/** /**
* Callback indicating the result of a characteristic write operation. * Callback indicating the result of a characteristic write operation.
* *
@@ -98,9 +116,12 @@ public abstract class BluetoothGattCallback {
* value to the desired value to be written. If the values don't match, * value to the desired value to be written. If the values don't match,
* the application must abort the reliable write transaction. * the application must abort the reliable write transaction.
* *
* @param gatt GATT client invoked {@link BluetoothGatt#writeCharacteristic} * @param gatt GATT client that invoked
* {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic,
* byte[], int)}
* @param characteristic Characteristic that was written to the associated remote device. * @param characteristic Characteristic that was written to the associated remote device.
* @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if the * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if
* the
* operation succeeds. * operation succeeds.
*/ */
public void onCharacteristicWrite(BluetoothGatt gatt, public void onCharacteristicWrite(BluetoothGatt gatt,
@@ -113,11 +134,29 @@ public abstract class BluetoothGattCallback {
* @param gatt GATT client the characteristic is associated with * @param gatt GATT client the characteristic is associated with
* @param characteristic Characteristic that has been updated as a result of a remote * @param characteristic Characteristic that has been updated as a result of a remote
* notification event. * notification event.
* @deprecated Use {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt,
* BluetoothGattCharacteristic, byte[])} as it is memory safe by providing the characteristic
* value at the time of notification.
*/ */
@Deprecated
public void onCharacteristicChanged(BluetoothGatt gatt, public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) { BluetoothGattCharacteristic characteristic) {
} }
/**
* Callback triggered as a result of a remote characteristic notification. Note that the value
* within the characteristic object may have changed since receiving the remote characteristic
* notification, so check the parameter value for the value at the time of notification.
*
* @param gatt GATT client the characteristic is associated with
* @param characteristic Characteristic that has been updated as a result of a remote
* notification event.
* @param value notified characteristic value
*/
public void onCharacteristicChanged(@NonNull BluetoothGatt gatt,
@NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) {
}
/** /**
* Callback reporting the result of a descriptor read operation. * Callback reporting the result of a descriptor read operation.
* *
@@ -125,11 +164,28 @@ public abstract class BluetoothGattCallback {
* @param descriptor Descriptor that was read from the associated remote device. * @param descriptor Descriptor that was read from the associated remote device.
* @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
* successfully * successfully
* @deprecated Use {@link BluetoothGattCallback#onDescriptorRead(BluetoothGatt,
* BluetoothGattDescriptor, int, byte[])} as it is memory safe by providing the descriptor
* value at the time it was read.
*/ */
@Deprecated
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status) { int status) {
} }
/**
* Callback reporting the result of a descriptor read operation.
*
* @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor}
* @param descriptor Descriptor that was read from the associated remote device.
* @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
* successfully
* @param value the descriptor value at the time of the read operation
*/
public void onDescriptorRead(@NonNull BluetoothGatt gatt,
@NonNull BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) {
}
/** /**
* Callback indicating the result of a descriptor write operation. * Callback indicating the result of a descriptor write operation.
* *

View File

@@ -451,8 +451,8 @@ public class BluetoothGattCharacteristic implements Parcelable {
* Set the write type for this characteristic * Set the write type for this characteristic
* *
* <p>Setting the write type of a characteristic determines how the * <p>Setting the write type of a characteristic determines how the
* {@link BluetoothGatt#writeCharacteristic} function write this * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} function
* characteristic. * write this characteristic.
* *
* @param writeType The write type to for this characteristic. Can be one of: {@link * @param writeType The write type to for this characteristic. Can be one of: {@link
* #WRITE_TYPE_DEFAULT}, {@link #WRITE_TYPE_NO_RESPONSE} or {@link #WRITE_TYPE_SIGNED}. * #WRITE_TYPE_DEFAULT}, {@link #WRITE_TYPE_NO_RESPONSE} or {@link #WRITE_TYPE_SIGNED}.
@@ -504,7 +504,10 @@ public class BluetoothGattCharacteristic implements Parcelable {
* operation or if a characteristic update notification has been received. * operation or if a characteristic update notification has been received.
* *
* @return Cached value of the characteristic * @return Cached value of the characteristic
*
* @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} instead
*/ */
@Deprecated
public byte[] getValue() { public byte[] getValue() {
return mValue; return mValue;
} }
@@ -521,7 +524,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
* @param formatType The format type used to interpret the characteristic value. * @param formatType The format type used to interpret the characteristic value.
* @param offset Offset at which the integer value can be found. * @param offset Offset at which the integer value can be found.
* @return Cached value of the characteristic or null of offset exceeds value size. * @return Cached value of the characteristic or null of offset exceeds value size.
*
* @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get
* the characteristic value
*/ */
@Deprecated
public Integer getIntValue(int formatType, int offset) { public Integer getIntValue(int formatType, int offset) {
if ((offset + getTypeLen(formatType)) > mValue.length) return null; if ((offset + getTypeLen(formatType)) > mValue.length) return null;
@@ -558,7 +565,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
* @param offset Offset at which the float value can be found. * @param offset Offset at which the float value can be found.
* @return Cached value of the characteristic at a given offset or null if the requested offset * @return Cached value of the characteristic at a given offset or null if the requested offset
* exceeds the value size. * exceeds the value size.
*
* @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get
* the characteristic value
*/ */
@Deprecated
public Float getFloatValue(int formatType, int offset) { public Float getFloatValue(int formatType, int offset) {
if ((offset + getTypeLen(formatType)) > mValue.length) return null; if ((offset + getTypeLen(formatType)) > mValue.length) return null;
@@ -580,7 +591,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
* *
* @param offset Offset at which the string value can be found. * @param offset Offset at which the string value can be found.
* @return Cached value of the characteristic * @return Cached value of the characteristic
*
* @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get
* the characteristic value
*/ */
@Deprecated
public String getStringValue(int offset) { public String getStringValue(int offset) {
if (mValue == null || offset > mValue.length) return null; if (mValue == null || offset > mValue.length) return null;
byte[] strBytes = new byte[mValue.length - offset]; byte[] strBytes = new byte[mValue.length - offset];
@@ -599,7 +614,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
* @param value New value for this characteristic * @param value New value for this characteristic
* @return true if the locally stored value has been set, false if the requested value could not * @return true if the locally stored value has been set, false if the requested value could not
* be stored locally. * be stored locally.
*
* @deprecated Pass the characteristic value directly into
* {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)}
*/ */
@Deprecated
public boolean setValue(byte[] value) { public boolean setValue(byte[] value) {
mValue = value; mValue = value;
return true; return true;
@@ -613,7 +632,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
* @param formatType Integer format type used to transform the value parameter * @param formatType Integer format type used to transform the value parameter
* @param offset Offset at which the value should be placed * @param offset Offset at which the value should be placed
* @return true if the locally stored value has been set * @return true if the locally stored value has been set
*
* @deprecated Pass the characteristic value directly into
* {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)}
*/ */
@Deprecated
public boolean setValue(int value, int formatType, int offset) { public boolean setValue(int value, int formatType, int offset) {
int len = offset + getTypeLen(formatType); int len = offset + getTypeLen(formatType);
if (mValue == null) mValue = new byte[len]; if (mValue == null) mValue = new byte[len];
@@ -660,7 +683,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
* @param formatType Float format type used to transform the value parameter * @param formatType Float format type used to transform the value parameter
* @param offset Offset at which the value should be placed * @param offset Offset at which the value should be placed
* @return true if the locally stored value has been set * @return true if the locally stored value has been set
*
* @deprecated Pass the characteristic value directly into
* {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)}
*/ */
@Deprecated
public boolean setValue(int mantissa, int exponent, int formatType, int offset) { public boolean setValue(int mantissa, int exponent, int formatType, int offset) {
int len = offset + getTypeLen(formatType); int len = offset + getTypeLen(formatType);
if (mValue == null) mValue = new byte[len]; if (mValue == null) mValue = new byte[len];
@@ -697,7 +724,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
* *
* @param value New value for this characteristic * @param value New value for this characteristic
* @return true if the locally stored value has been set * @return true if the locally stored value has been set
*
* @deprecated Pass the characteristic value directly into
* {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)}
*/ */
@Deprecated
public boolean setValue(String value) { public boolean setValue(String value) {
mValue = value.getBytes(); mValue = value.getBytes();
return true; return true;

View File

@@ -260,7 +260,10 @@ public class BluetoothGattDescriptor implements Parcelable {
* operation. * operation.
* *
* @return Cached value of the descriptor * @return Cached value of the descriptor
*
* @deprecated Use {@link BluetoothGatt#readDescriptor(BluetoothGattDescriptor)} instead
*/ */
@Deprecated
public byte[] getValue() { public byte[] getValue() {
return mValue; return mValue;
} }
@@ -276,7 +279,11 @@ public class BluetoothGattDescriptor implements Parcelable {
* @param value New value for this descriptor * @param value New value for this descriptor
* @return true if the locally stored value has been set, false if the requested value could not * @return true if the locally stored value has been set, false if the requested value could not
* be stored locally. * be stored locally.
*
* @deprecated Pass the descriptor value directly into
* {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])}
*/ */
@Deprecated
public boolean setValue(byte[] value) { public boolean setValue(byte[] value) {
mValue = value; mValue = value;
return true; return true;

View File

@@ -78,10 +78,32 @@ public final class BluetoothStatusCodes {
*/ */
public static final int ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION = 7; public static final int ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION = 7;
/**
* Error code indicating that the caller does not have the
* {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission
*/
public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8;
/**
* Error code indicating that the profile service is not bound. You can bind a profile service
* by calling {@link BluetoothAdapter#getProfileProxy}
*/
public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9;
/** /**
* Error code indicating that the feature is not supported. * Error code indicating that the feature is not supported.
*/ */
public static final int ERROR_FEATURE_NOT_SUPPORTED = 8; public static final int ERROR_FEATURE_NOT_SUPPORTED = 10;
/**
* A GATT writeCharacteristic request is not permitted on the remote device.
*/
public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101;
/**
* A GATT writeCharacteristic request is issued to a busy remote device.
*/
public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102;
/** /**
* If another application has already requested {@link OobData} then another fetch will be * If another application has already requested {@link OobData} then another fetch will be