Add new @SystemApi for specifying AddressType and IRK

Bug: 178234318
Test: compiles and runs
Tag: #feature
Change-Id: Ib67e681af01260df98602003b2aca47963494c6f
This commit is contained in:
Martin Brabham
2021-03-16 21:14:40 -07:00
parent 55fe87b2f6
commit 045fe260e1
5 changed files with 212 additions and 5 deletions

View File

@@ -8689,6 +8689,8 @@ package android.bluetooth {
field public static final String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
field public static final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
field public static final String ACTION_UUID = "android.bluetooth.device.action.UUID";
field public static final int ADDRESS_TYPE_PUBLIC = 0; // 0x0
field public static final int ADDRESS_TYPE_RANDOM = 1; // 0x1
field public static final int BOND_BONDED = 12; // 0xc
field public static final int BOND_BONDING = 11; // 0xb
field public static final int BOND_NONE = 10; // 0xa

View File

@@ -1726,6 +1726,17 @@ package android.bluetooth.le {
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.ResultStorageDescriptor> CREATOR;
}
public final class ScanFilter implements android.os.Parcelable {
method public int getAddressType();
method @Nullable public byte[] getIrk();
}
public static final class ScanFilter.Builder {
method @NonNull public android.bluetooth.le.ScanFilter.Builder setDeviceAddress(@NonNull String, int);
method @NonNull public android.bluetooth.le.ScanFilter.Builder setDeviceAddress(@NonNull String, int, @NonNull byte[]);
field public static final int LEN_IRK_OCTETS = 16; // 0x10
}
public final class ScanSettings implements android.os.Parcelable {
field public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; // 0x1
field public static final int SCAN_RESULT_TYPE_FULL = 0; // 0x0

View File

@@ -52,6 +52,8 @@ import android.os.SystemProperties;
import android.util.Log;
import android.util.Pair;
import com.android.internal.util.Preconditions;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -3118,6 +3120,25 @@ public final class BluetoothAdapter {
return true;
}
/**
* Determines whether a String Bluetooth address, such as "00:43:A8:23:10:F0"
* is a RANDOM STATIC address.
*
* RANDOM STATIC: (addr & 0b11) == 0b11
* RANDOM RESOLVABLE: (addr & 0b11) == 0b10
* RANDOM non-RESOLVABLE: (addr & 0b11) == 0b00
*
* @param address Bluetooth address as string
* @return true if the 2 Least Significant Bits of the address equals 0b11.
*
* @hide
*/
public static boolean isAddressRandomStatic(@NonNull String address) {
Preconditions.checkNotNull(address);
return checkBluetoothAddress(address)
&& (Integer.parseInt(address.split(":")[5], 16) & 0b11) == 0b11;
}
@UnsupportedAppUsage
/*package*/ IBluetoothManager getBluetoothManager() {
return mManagerService;

View File

@@ -1002,6 +1002,24 @@ public final class BluetoothDevice implements Parcelable {
public static final String EXTRA_MAS_INSTANCE =
"android.bluetooth.device.extra.MAS_INSTANCE";
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(
prefix = { "ADDRESS_TYPE_" },
value = {
/** Hardware MAC Address */
ADDRESS_TYPE_PUBLIC,
/** Address is either resolvable, non-resolvable or static.*/
ADDRESS_TYPE_RANDOM,
}
)
public @interface AddressType {}
/** Hardware MAC Address of the device */
public static final int ADDRESS_TYPE_PUBLIC = 0;
/** Address is either resolvable, non-resolvable or static. */
public static final int ADDRESS_TYPE_RANDOM = 1;
/**
* Lazy initialization. Guaranteed final after first object constructed, or
* getService() called.
@@ -1010,6 +1028,7 @@ public final class BluetoothDevice implements Parcelable {
private static volatile IBluetooth sService;
private final String mAddress;
@AddressType private final int mAddressType;
/*package*/
@UnsupportedAppUsage
@@ -1064,6 +1083,7 @@ public final class BluetoothDevice implements Parcelable {
}
mAddress = address;
mAddressType = ADDRESS_TYPE_PUBLIC;
}
@Override

View File

@@ -16,15 +16,19 @@
package android.bluetooth.le;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevice.AddressType;
import android.os.Parcel;
import android.os.ParcelUuid;
import android.os.Parcelable;
import com.android.internal.util.BitUtils;
import com.android.internal.util.Preconditions;
import java.util.Arrays;
import java.util.List;
@@ -53,6 +57,11 @@ public final class ScanFilter implements Parcelable {
@Nullable
private final String mDeviceAddress;
private final @AddressType int mAddressType;
@Nullable
private final byte[] mIrk;
@Nullable
private final ParcelUuid mServiceUuid;
@Nullable
@@ -79,12 +88,12 @@ public final class ScanFilter implements Parcelable {
/** @hide */
public static final ScanFilter EMPTY = new ScanFilter.Builder().build();
private ScanFilter(String name, String deviceAddress, ParcelUuid uuid,
ParcelUuid uuidMask, ParcelUuid solicitationUuid,
ParcelUuid solicitationUuidMask, ParcelUuid serviceDataUuid,
byte[] serviceData, byte[] serviceDataMask,
int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask) {
int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask,
@AddressType int addressType, @Nullable byte[] irk) {
mDeviceName = name;
mServiceUuid = uuid;
mServiceUuidMask = uuidMask;
@@ -97,6 +106,8 @@ public final class ScanFilter implements Parcelable {
mManufacturerId = manufacturerId;
mManufacturerData = manufacturerData;
mManufacturerDataMask = manufacturerDataMask;
mAddressType = addressType;
mIrk = irk;
}
@Override
@@ -280,6 +291,23 @@ public final class ScanFilter implements Parcelable {
return mDeviceAddress;
}
/**
* @hide
*/
@SystemApi
public @AddressType int getAddressType() {
return mAddressType;
}
/**
* @hide
*/
@SystemApi
@Nullable
public byte[] getIrk() {
return mIrk;
}
@Nullable
public byte[] getServiceData() {
return mServiceData;
@@ -516,8 +544,16 @@ public final class ScanFilter implements Parcelable {
*/
public static final class Builder {
/**
* @hide
*/
@SystemApi
public static final int LEN_IRK_OCTETS = 16;
private String mDeviceName;
private String mDeviceAddress;
private @AddressType int mAddressType = BluetoothDevice.ADDRESS_TYPE_PUBLIC;
private byte[] mIrk;
private ParcelUuid mServiceUuid;
private ParcelUuid mUuidMask;
@@ -546,14 +582,130 @@ public final class ScanFilter implements Parcelable {
*
* @param deviceAddress The device Bluetooth address for the filter. It needs to be in the
* format of "01:02:03:AB:CD:EF". The device address can be validated using {@link
* BluetoothAdapter#checkBluetoothAddress}.
* BluetoothAdapter#checkBluetoothAddress}. The @AddressType is defaulted to {@link
* BluetoothDevice#ADDRESS_TYPE_PUBLIC}
* @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
*/
public Builder setDeviceAddress(String deviceAddress) {
if (deviceAddress != null && !BluetoothAdapter.checkBluetoothAddress(deviceAddress)) {
return setDeviceAddress(mDeviceAddress, BluetoothDevice.ADDRESS_TYPE_PUBLIC);
}
/**
* Set filter on Address with AddressType
*
* <p>This key is used to resolve a private address from a public address.
*
* @param deviceAddress The device Bluetooth address for the filter. It needs to be in the
* format of "01:02:03:AB:CD:EF". The device address can be validated using {@link
* BluetoothAdapter#checkBluetoothAddress}. May be any type of address.
* @param addressType indication of the type of address
* e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC}
* or {@link BluetoothDevice#ADDRESS_TYPE_RANDOM}
*
* @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
* @throws IllegalArgumentException If the {@code addressType} is invalid length
* @throws NullPointerException if {@code deviceAddress} is null.
*
* @hide
*/
@NonNull
@SystemApi
public Builder setDeviceAddress(@NonNull String deviceAddress,
@AddressType int addressType) {
return setDeviceAddressInternal(deviceAddress, addressType, null);
}
/**
* Set filter on Address with AddressType and the Identity Resolving Key (IRK).
*
* <p>The IRK is used to resolve a {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} from
* a PRIVATE_ADDRESS type.
*
* @param deviceAddress The device Bluetooth address for the filter. It needs to be in the
* format of "01:02:03:AB:CD:EF". The device address can be validated using {@link
* BluetoothAdapter#checkBluetoothAddress}. This Address type must only be PUBLIC OR RANDOM
* STATIC.
* @param addressType indication of the type of address
* e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC}
* or {@link BluetoothDevice#ADDRESS_TYPE_RANDOM}
* @param irk non-null byte array representing the Identity Resolving Key
*
* @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
* @throws IllegalArgumentException if the {@code irk} is invalid length.
* @throws IllegalArgumentException If the {@code addressType} is invalid length or is not
* PUBLIC or RANDOM STATIC when an IRK is present.
* @throws NullPointerException if {@code deviceAddress} or {@code irk} is null.
*
* @hide
*/
@NonNull
@SystemApi
public Builder setDeviceAddress(@NonNull String deviceAddress,
@AddressType int addressType,
@NonNull byte[] irk) {
Preconditions.checkNotNull(irk);
if (irk.length != LEN_IRK_OCTETS) {
throw new IllegalArgumentException("'irk' is invalid length!");
}
return setDeviceAddressInternal(deviceAddress, addressType, irk);
}
/**
* Set filter on Address with AddressType and the Identity Resolving Key (IRK).
*
* <p>Internal setter for the device address
*
* @param deviceAddress The device Bluetooth address for the filter. It needs to be in the
* format of "01:02:03:AB:CD:EF". The device address can be validated using {@link
* BluetoothAdapter#checkBluetoothAddress}.
* @param addressType indication of the type of address
* e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC}
* @param irk non-null byte array representing the Identity Resolving Address; nullable
* internally.
*
* @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
* @throws IllegalArgumentException If the {@code addressType} is invalid length.
* @throws NullPointerException if {@code deviceAddress} is null.
*
* @hide
*/
@NonNull
private Builder setDeviceAddressInternal(@NonNull String deviceAddress,
@AddressType int addressType,
@Nullable byte[] irk) {
// Make sure our deviceAddress is valid!
Preconditions.checkNotNull(deviceAddress);
if (!BluetoothAdapter.checkBluetoothAddress(deviceAddress)) {
throw new IllegalArgumentException("invalid device address " + deviceAddress);
}
// Verify type range
if (addressType < BluetoothDevice.ADDRESS_TYPE_PUBLIC
|| addressType > BluetoothDevice.ADDRESS_TYPE_RANDOM) {
throw new IllegalArgumentException("'addressType' is invalid!");
}
// IRK can only be used for a PUBLIC or RANDOM (STATIC) Address.
if (addressType == BluetoothDevice.ADDRESS_TYPE_RANDOM) {
// Don't want a bad combination of address and irk!
if (irk != null) {
// Since there are 3 possible RANDOM subtypes we must check to make sure
// the correct type of address is used.
if (!BluetoothAdapter.isAddressRandomStatic(deviceAddress)) {
throw new IllegalArgumentException(
"Invalid combination: IRK requires either a PUBLIC or "
+ "RANDOM (STATIC) Address");
}
}
}
// PUBLIC doesn't require extra work
// Without an IRK any address may be accepted
mDeviceAddress = deviceAddress;
mAddressType = addressType;
mIrk = irk;
return this;
}
@@ -727,7 +879,8 @@ public final class ScanFilter implements Parcelable {
mServiceUuid, mUuidMask, mServiceSolicitationUuid,
mServiceSolicitationUuidMask,
mServiceDataUuid, mServiceData, mServiceDataMask,
mManufacturerId, mManufacturerData, mManufacturerDataMask);
mManufacturerId, mManufacturerData, mManufacturerDataMask,
mAddressType, mIrk);
}
}
}