Merge "Add new @SystemApi for specifying AddressType and IRK" am: bf516b9e11

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

Change-Id: I616502ee58d95cbc20fd38b395f7f0e294b5713e
This commit is contained in:
Treehugger Robot
2021-03-22 03:15:47 +00:00
committed by Automerger Merge Worker
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_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_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
field public static final String ACTION_UUID = "android.bluetooth.device.action.UUID"; 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_BONDED = 12; // 0xc
field public static final int BOND_BONDING = 11; // 0xb field public static final int BOND_BONDING = 11; // 0xb
field public static final int BOND_NONE = 10; // 0xa field public static final int BOND_NONE = 10; // 0xa

View File

@@ -1728,6 +1728,17 @@ package android.bluetooth.le {
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.ResultStorageDescriptor> CREATOR; 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 { public final class ScanSettings implements android.os.Parcelable {
field public static final int SCAN_MODE_AMBIENT_DISCOVERY = 3; // 0x3 field public static final int SCAN_MODE_AMBIENT_DISCOVERY = 3; // 0x3
field public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; // 0x1 field public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; // 0x1

View File

@@ -52,6 +52,8 @@ import android.os.SystemProperties;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import com.android.internal.util.Preconditions;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@@ -3118,6 +3120,25 @@ public final class BluetoothAdapter {
return true; 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 @UnsupportedAppUsage
/*package*/ IBluetoothManager getBluetoothManager() { /*package*/ IBluetoothManager getBluetoothManager() {
return mManagerService; return mManagerService;

View File

@@ -1002,6 +1002,24 @@ public final class BluetoothDevice implements Parcelable {
public static final String EXTRA_MAS_INSTANCE = public static final String EXTRA_MAS_INSTANCE =
"android.bluetooth.device.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 * Lazy initialization. Guaranteed final after first object constructed, or
* getService() called. * getService() called.
@@ -1010,6 +1028,7 @@ public final class BluetoothDevice implements Parcelable {
private static volatile IBluetooth sService; private static volatile IBluetooth sService;
private final String mAddress; private final String mAddress;
@AddressType private final int mAddressType;
/*package*/ /*package*/
@UnsupportedAppUsage @UnsupportedAppUsage
@@ -1064,6 +1083,7 @@ public final class BluetoothDevice implements Parcelable {
} }
mAddress = address; mAddress = address;
mAddressType = ADDRESS_TYPE_PUBLIC;
} }
@Override @Override

View File

@@ -16,15 +16,19 @@
package android.bluetooth.le; package android.bluetooth.le;
import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevice.AddressType;
import android.os.Parcel; import android.os.Parcel;
import android.os.ParcelUuid; import android.os.ParcelUuid;
import android.os.Parcelable; import android.os.Parcelable;
import com.android.internal.util.BitUtils; import com.android.internal.util.BitUtils;
import com.android.internal.util.Preconditions;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -53,6 +57,11 @@ public final class ScanFilter implements Parcelable {
@Nullable @Nullable
private final String mDeviceAddress; private final String mDeviceAddress;
private final @AddressType int mAddressType;
@Nullable
private final byte[] mIrk;
@Nullable @Nullable
private final ParcelUuid mServiceUuid; private final ParcelUuid mServiceUuid;
@Nullable @Nullable
@@ -79,12 +88,12 @@ public final class ScanFilter implements Parcelable {
/** @hide */ /** @hide */
public static final ScanFilter EMPTY = new ScanFilter.Builder().build(); public static final ScanFilter EMPTY = new ScanFilter.Builder().build();
private ScanFilter(String name, String deviceAddress, ParcelUuid uuid, private ScanFilter(String name, String deviceAddress, ParcelUuid uuid,
ParcelUuid uuidMask, ParcelUuid solicitationUuid, ParcelUuid uuidMask, ParcelUuid solicitationUuid,
ParcelUuid solicitationUuidMask, ParcelUuid serviceDataUuid, ParcelUuid solicitationUuidMask, ParcelUuid serviceDataUuid,
byte[] serviceData, byte[] serviceDataMask, byte[] serviceData, byte[] serviceDataMask,
int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask) { int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask,
@AddressType int addressType, @Nullable byte[] irk) {
mDeviceName = name; mDeviceName = name;
mServiceUuid = uuid; mServiceUuid = uuid;
mServiceUuidMask = uuidMask; mServiceUuidMask = uuidMask;
@@ -97,6 +106,8 @@ public final class ScanFilter implements Parcelable {
mManufacturerId = manufacturerId; mManufacturerId = manufacturerId;
mManufacturerData = manufacturerData; mManufacturerData = manufacturerData;
mManufacturerDataMask = manufacturerDataMask; mManufacturerDataMask = manufacturerDataMask;
mAddressType = addressType;
mIrk = irk;
} }
@Override @Override
@@ -280,6 +291,23 @@ public final class ScanFilter implements Parcelable {
return mDeviceAddress; return mDeviceAddress;
} }
/**
* @hide
*/
@SystemApi
public @AddressType int getAddressType() {
return mAddressType;
}
/**
* @hide
*/
@SystemApi
@Nullable
public byte[] getIrk() {
return mIrk;
}
@Nullable @Nullable
public byte[] getServiceData() { public byte[] getServiceData() {
return mServiceData; return mServiceData;
@@ -516,8 +544,16 @@ public final class ScanFilter implements Parcelable {
*/ */
public static final class Builder { public static final class Builder {
/**
* @hide
*/
@SystemApi
public static final int LEN_IRK_OCTETS = 16;
private String mDeviceName; private String mDeviceName;
private String mDeviceAddress; private String mDeviceAddress;
private @AddressType int mAddressType = BluetoothDevice.ADDRESS_TYPE_PUBLIC;
private byte[] mIrk;
private ParcelUuid mServiceUuid; private ParcelUuid mServiceUuid;
private ParcelUuid mUuidMask; 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 * @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 * 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. * @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
*/ */
public Builder setDeviceAddress(String deviceAddress) { 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); 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; mDeviceAddress = deviceAddress;
mAddressType = addressType;
mIrk = irk;
return this; return this;
} }
@@ -727,7 +879,8 @@ public final class ScanFilter implements Parcelable {
mServiceUuid, mUuidMask, mServiceSolicitationUuid, mServiceUuid, mUuidMask, mServiceSolicitationUuid,
mServiceSolicitationUuidMask, mServiceSolicitationUuidMask,
mServiceDataUuid, mServiceData, mServiceDataMask, mServiceDataUuid, mServiceData, mServiceDataMask,
mManufacturerId, mManufacturerData, mManufacturerDataMask); mManufacturerId, mManufacturerData, mManufacturerDataMask,
mAddressType, mIrk);
} }
} }
} }