Merge "Refine Bluetooth Metadata API"

am: e5cf74326d

Change-Id: I8b7e9137f67dfa27dd1556f49bdd4cc702015150
This commit is contained in:
Ugo Yu
2019-04-15 14:01:00 -07:00
committed by android-build-merger
3 changed files with 124 additions and 92 deletions

View File

@@ -727,30 +727,29 @@ package android.app.usage {
package android.bluetooth { package android.bluetooth {
public final class BluetoothAdapter { public final class BluetoothAdapter {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
method public boolean disableBLE(); method public boolean disableBLE();
method public boolean enableBLE(); method public boolean enableBLE();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect();
method public boolean isBleScanAlwaysAvailable(); method public boolean isBleScanAlwaysAvailable();
method public boolean isLeEnabled(); method public boolean isLeEnabled();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean registerMetadataListener(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothAdapter.MetadataListener, android.os.Handler); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean unregisterMetadataListener(android.bluetooth.BluetoothDevice);
field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE"; field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
} }
public abstract static class BluetoothAdapter.MetadataListener { public static interface BluetoothAdapter.OnMetadataChangedListener {
ctor public BluetoothAdapter.MetadataListener(); method public void onMetadataChanged(@NonNull android.bluetooth.BluetoothDevice, int, @Nullable byte[]);
method public void onMetadataChanged(android.bluetooth.BluetoothDevice, int, String);
} }
public final class BluetoothDevice implements android.os.Parcelable { public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public String getMetadata(int); method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, String); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean);
field public static final int ACCESS_ALLOWED = 1; // 0x1 field public static final int ACCESS_ALLOWED = 1; // 0x1
@@ -760,21 +759,21 @@ package android.bluetooth {
field public static final int METADATA_COMPANION_APP = 4; // 0x4 field public static final int METADATA_COMPANION_APP = 4; // 0x4
field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10 field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3 field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
field public static final int METADATA_IS_UNTHETHERED_HEADSET = 6; // 0x6 field public static final int METADATA_IS_UNTETHERED_HEADSET = 6; // 0x6
field public static final int METADATA_MAIN_ICON = 5; // 0x5 field public static final int METADATA_MAIN_ICON = 5; // 0x5
field public static final int METADATA_MANUFACTURER_NAME = 0; // 0x0 field public static final int METADATA_MANUFACTURER_NAME = 0; // 0x0
field public static final int METADATA_MAX_LENGTH = 2048; // 0x800 field public static final int METADATA_MAX_LENGTH = 2048; // 0x800
field public static final int METADATA_MODEL_NAME = 1; // 0x1 field public static final int METADATA_MODEL_NAME = 1; // 0x1
field public static final int METADATA_SOFTWARE_VERSION = 2; // 0x2 field public static final int METADATA_SOFTWARE_VERSION = 2; // 0x2
field public static final int METADATA_UNTHETHERED_CASE_BATTERY = 12; // 0xc field public static final int METADATA_UNTETHERED_CASE_BATTERY = 12; // 0xc
field public static final int METADATA_UNTHETHERED_CASE_CHARGING = 15; // 0xf field public static final int METADATA_UNTETHERED_CASE_CHARGING = 15; // 0xf
field public static final int METADATA_UNTHETHERED_CASE_ICON = 9; // 0x9 field public static final int METADATA_UNTETHERED_CASE_ICON = 9; // 0x9
field public static final int METADATA_UNTHETHERED_LEFT_BATTERY = 10; // 0xa field public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10; // 0xa
field public static final int METADATA_UNTHETHERED_LEFT_CHARGING = 13; // 0xd field public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13; // 0xd
field public static final int METADATA_UNTHETHERED_LEFT_ICON = 7; // 0x7 field public static final int METADATA_UNTETHERED_LEFT_ICON = 7; // 0x7
field public static final int METADATA_UNTHETHERED_RIGHT_BATTERY = 11; // 0xb field public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11; // 0xb
field public static final int METADATA_UNTHETHERED_RIGHT_CHARGING = 14; // 0xe field public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14; // 0xe
field public static final int METADATA_UNTHETHERED_RIGHT_ICON = 8; // 0x8 field public static final int METADATA_UNTETHERED_RIGHT_ICON = 8; // 0x8
} }
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile { public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {

View File

@@ -20,6 +20,7 @@ package android.bluetooth;
import android.Manifest; import android.Manifest;
import android.annotation.IntDef; import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission; import android.annotation.RequiresPermission;
import android.annotation.SdkConstant; import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SdkConstant.SdkConstantType;
@@ -37,7 +38,6 @@ import android.bluetooth.le.ScanSettings;
import android.content.Context; import android.content.Context;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.os.Binder; import android.os.Binder;
import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.ParcelUuid; import android.os.ParcelUuid;
import android.os.RemoteException; import android.os.RemoteException;
@@ -61,6 +61,7 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -650,7 +651,7 @@ public final class BluetoothAdapter {
private final Object mLock = new Object(); private final Object mLock = new Object();
private final Map<LeScanCallback, ScanCallback> mLeScanClients; private final Map<LeScanCallback, ScanCallback> mLeScanClients;
private static final Map<BluetoothDevice, List<Pair<MetadataListener, Handler>>> private static final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
sMetadataListeners = new HashMap<>(); sMetadataListeners = new HashMap<>();
/** /**
@@ -660,14 +661,15 @@ public final class BluetoothAdapter {
private static final IBluetoothMetadataListener sBluetoothMetadataListener = private static final IBluetoothMetadataListener sBluetoothMetadataListener =
new IBluetoothMetadataListener.Stub() { new IBluetoothMetadataListener.Stub() {
@Override @Override
public void onMetadataChanged(BluetoothDevice device, int key, String value) { public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) {
synchronized (sMetadataListeners) { synchronized (sMetadataListeners) {
if (sMetadataListeners.containsKey(device)) { if (sMetadataListeners.containsKey(device)) {
List<Pair<MetadataListener, Handler>> list = sMetadataListeners.get(device); List<Pair<OnMetadataChangedListener, Executor>> list =
for (Pair<MetadataListener, Handler> pair : list) { sMetadataListeners.get(device);
MetadataListener listener = pair.first; for (Pair<OnMetadataChangedListener, Executor> pair : list) {
Handler handler = pair.second; OnMetadataChangedListener listener = pair.first;
handler.post(() -> { Executor executor = pair.second;
executor.execute(() -> {
listener.onMetadataChanged(device, key, value); listener.onMetadataChanged(device, key, value);
}); });
} }
@@ -3153,30 +3155,30 @@ public final class BluetoothAdapter {
} }
/** /**
* Register a {@link #MetadataListener} to receive update about metadata * Register a {@link #OnMetadataChangedListener} to receive update about metadata
* changes for this {@link BluetoothDevice}. * changes for this {@link BluetoothDevice}.
* Registration must be done when Bluetooth is ON and will last until * Registration must be done when Bluetooth is ON and will last until
* {@link #unregisterMetadataListener(BluetoothDevice)} is called, even when Bluetooth * {@link #removeOnMetadataChangedListener(BluetoothDevice)} is called, even when Bluetooth
* restarted in the middle. * restarted in the middle.
* All input parameters should not be null or {@link NullPointerException} will be triggered. * All input parameters should not be null or {@link NullPointerException} will be triggered.
* The same {@link BluetoothDevice} and {@link #MetadataListener} pair can only be registered * The same {@link BluetoothDevice} and {@link #OnMetadataChangedListener} pair can only be
* once, double registration would cause {@link IllegalArgumentException}. * registered once, double registration would cause {@link IllegalArgumentException}.
* *
* @param device {@link BluetoothDevice} that will be registered * @param device {@link BluetoothDevice} that will be registered
* @param listener {@link #MetadataListener} that will receive asynchronous callbacks * @param executor the executor for listener callback
* @param handler the handler for listener callback * @param listener {@link #OnMetadataChangedListener} that will receive asynchronous callbacks
* @return true on success, false on error * @return true on success, false on error
* @throws NullPointerException If one of {@code listener}, {@code device} or {@code handler} * @throws NullPointerException If one of {@code listener}, {@code device} or {@code executor}
* is null. * is null.
* @throws IllegalArgumentException The same {@link #MetadataListener} and * @throws IllegalArgumentException The same {@link #OnMetadataChangedListener} and
* {@link BluetoothDevice} are registered twice. * {@link BluetoothDevice} are registered twice.
* @hide * @hide
*/ */
@SystemApi @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean registerMetadataListener(BluetoothDevice device, MetadataListener listener, public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device,
Handler handler) { @NonNull Executor executor, @NonNull OnMetadataChangedListener listener) {
if (DBG) Log.d(TAG, "registerMetdataListener()"); if (DBG) Log.d(TAG, "addOnMetadataChangedListener()");
final IBluetooth service = mService; final IBluetooth service = mService;
if (service == null) { if (service == null) {
@@ -3189,14 +3191,15 @@ public final class BluetoothAdapter {
if (device == null) { if (device == null) {
throw new NullPointerException("device is null"); throw new NullPointerException("device is null");
} }
if (handler == null) { if (executor == null) {
throw new NullPointerException("handler is null"); throw new NullPointerException("executor is null");
} }
synchronized (sMetadataListeners) { synchronized (sMetadataListeners) {
List<Pair<MetadataListener, Handler>> listenerList = sMetadataListeners.get(device); List<Pair<OnMetadataChangedListener, Executor>> listenerList =
sMetadataListeners.get(device);
if (listenerList == null) { if (listenerList == null) {
// Create new listener/handler list for registeration // Create new listener/executor list for registeration
listenerList = new ArrayList<>(); listenerList = new ArrayList<>();
sMetadataListeners.put(device, listenerList); sMetadataListeners.put(device, listenerList);
} else { } else {
@@ -3207,7 +3210,7 @@ public final class BluetoothAdapter {
} }
} }
Pair<MetadataListener, Handler> listenerPair = new Pair(listener, handler); Pair<OnMetadataChangedListener, Executor> listenerPair = new Pair(listener, executor);
listenerList.add(listenerPair); listenerList.add(listenerPair);
boolean ret = false; boolean ret = false;
@@ -3230,63 +3233,74 @@ public final class BluetoothAdapter {
} }
/** /**
* Unregister all {@link MetadataListener} from this {@link BluetoothDevice}. * Unregister a {@link #OnMetadataChangedListener} from a registered {@link BluetoothDevice}.
* Unregistration can be done when Bluetooth is either ON or OFF. * Unregistration can be done when Bluetooth is either ON or OFF.
* {@link #registerMetadataListener(MetadataListener, BluetoothDevice, Handler)} must * {@link #addOnMetadataChangedListener(OnMetadataChangedListener, BluetoothDevice, Executor)}
* be called before unregisteration. * must be called before unregisteration.
* Unregistering a device that is not regestered would cause {@link IllegalArgumentException}.
* *
* @param device {@link BluetoothDevice} that will be unregistered. it * @param device {@link BluetoothDevice} that will be unregistered. It
* should not be null or {@link NullPointerException} will be triggered.
* @param listener {@link OnMetadataChangedListener} that will be unregistered. It
* should not be null or {@link NullPointerException} will be triggered. * should not be null or {@link NullPointerException} will be triggered.
* @return true on success, false on error * @return true on success, false on error
* @throws NullPointerException If {@code device} is null. * @throws NullPointerException If {@code listener} or {@code device} is null.
* @throws IllegalArgumentException If {@code device} has not been registered before. * @throws IllegalArgumentException If {@code device} has not been registered before.
* @hide * @hide
*/ */
@SystemApi @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean unregisterMetadataListener(BluetoothDevice device) { public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device,
if (DBG) Log.d(TAG, "unregisterMetdataListener()"); @NonNull OnMetadataChangedListener listener) {
if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()");
if (device == null) { if (device == null) {
throw new NullPointerException("device is null"); throw new NullPointerException("device is null");
} }
if (listener == null) {
throw new NullPointerException("listener is null");
}
synchronized (sMetadataListeners) { synchronized (sMetadataListeners) {
if (sMetadataListeners.containsKey(device)) { if (!sMetadataListeners.containsKey(device)) {
sMetadataListeners.remove(device);
} else {
throw new IllegalArgumentException("device was not registered"); throw new IllegalArgumentException("device was not registered");
} }
// Remove issued listener from the registered device
sMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener)));
final IBluetooth service = mService; if (sMetadataListeners.get(device).isEmpty()) {
if (service == null) { // Unregister to Bluetooth service if all listeners are removed from
// Bluetooth is OFF, do nothing to Bluetooth service. // the registered device
return true; sMetadataListeners.remove(device);
} final IBluetooth service = mService;
try { if (service == null) {
return service.unregisterMetadataListener(device); // Bluetooth is OFF, do nothing to Bluetooth service.
} catch (RemoteException e) { return true;
Log.e(TAG, "unregisterMetadataListener fail", e); }
return false; try {
return service.unregisterMetadataListener(device);
} catch (RemoteException e) {
Log.e(TAG, "unregisterMetadataListener fail", e);
return false;
}
} }
} }
return true;
} }
/** /**
* This abstract class is used to implement {@link BluetoothAdapter} metadata listener. * This interface is used to implement {@link BluetoothAdapter} metadata listener.
* @hide * @hide
*/ */
@SystemApi @SystemApi
public abstract static class MetadataListener { public interface OnMetadataChangedListener {
/** /**
* Callback triggered if the metadata of {@link BluetoothDevice} registered in * Callback triggered if the metadata of {@link BluetoothDevice} registered in
* {@link #registerMetadataListener}. * {@link #addOnMetadataChangedListener}.
* *
* @param device changed {@link BluetoothDevice}. * @param device changed {@link BluetoothDevice}.
* @param key changed metadata key, one of BluetoothDevice.METADATA_*. * @param key changed metadata key, one of BluetoothDevice.METADATA_*.
* @param value the new value of metadata. * @param value the new value of metadata as byte array.
*/ */
public void onMetadataChanged(BluetoothDevice device, int key, String value) { void onMetadataChanged(@NonNull BluetoothDevice device, int key,
} @Nullable byte[] value);
} }
} }

View File

@@ -18,6 +18,7 @@ package android.bluetooth;
import android.Manifest; import android.Manifest;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission; import android.annotation.RequiresPermission;
import android.annotation.SdkConstant; import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SdkConstant.SdkConstantType;
@@ -351,6 +352,7 @@ public final class BluetoothDevice implements Parcelable {
/** /**
* Manufacturer name of this Bluetooth device * Manufacturer name of this Bluetooth device
* Data type should be {@String} as {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
@@ -358,6 +360,7 @@ public final class BluetoothDevice implements Parcelable {
/** /**
* Model name of this Bluetooth device * Model name of this Bluetooth device
* Data type should be {@String} as {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
@@ -365,6 +368,7 @@ public final class BluetoothDevice implements Parcelable {
/** /**
* Software version of this Bluetooth device * Software version of this Bluetooth device
* Data type should be {@String} as {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
@@ -372,6 +376,7 @@ public final class BluetoothDevice implements Parcelable {
/** /**
* Hardware version of this Bluetooth device * Hardware version of this Bluetooth device
* Data type should be {@String} as {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
@@ -379,6 +384,7 @@ public final class BluetoothDevice implements Parcelable {
/** /**
* Package name of the companion app, if any * Package name of the companion app, if any
* Data type should be {@String} as {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
@@ -386,6 +392,7 @@ public final class BluetoothDevice implements Parcelable {
/** /**
* URI to the main icon shown on the settings UI * URI to the main icon shown on the settings UI
* Data type should be {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
@@ -393,80 +400,91 @@ public final class BluetoothDevice implements Parcelable {
/** /**
* Whether this device is an untethered headset with left, right and case * Whether this device is an untethered headset with left, right and case
* Data type should be {@String} as {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
public static final int METADATA_IS_UNTHETHERED_HEADSET = 6; public static final int METADATA_IS_UNTETHERED_HEADSET = 6;
/** /**
* URI to icon of the left headset * URI to icon of the left headset
* Data type should be {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
public static final int METADATA_UNTHETHERED_LEFT_ICON = 7; public static final int METADATA_UNTETHERED_LEFT_ICON = 7;
/** /**
* URI to icon of the right headset * URI to icon of the right headset
* Data type should be {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
public static final int METADATA_UNTHETHERED_RIGHT_ICON = 8; public static final int METADATA_UNTETHERED_RIGHT_ICON = 8;
/** /**
* URI to icon of the headset charging case * URI to icon of the headset charging case
* Data type should be {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
public static final int METADATA_UNTHETHERED_CASE_ICON = 9; public static final int METADATA_UNTETHERED_CASE_ICON = 9;
/** /**
* Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN} * Battery level of left headset
* is invalid, of the left headset * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
* as invalid.
* @hide * @hide
*/ */
@SystemApi @SystemApi
public static final int METADATA_UNTHETHERED_LEFT_BATTERY = 10; public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10;
/** /**
* Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN} * Battery level of rigth headset
* is invalid, of the right headset * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
* as invalid.
* @hide * @hide
*/ */
@SystemApi @SystemApi
public static final int METADATA_UNTHETHERED_RIGHT_BATTERY = 11; public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11;
/** /**
* Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN} * Battery level of the headset charging case
* is invalid, of the headset charging case * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
* as invalid.
* @hide * @hide
*/ */
@SystemApi @SystemApi
public static final int METADATA_UNTHETHERED_CASE_BATTERY = 12; public static final int METADATA_UNTETHERED_CASE_BATTERY = 12;
/** /**
* Whether the left headset is charging * Whether the left headset is charging
* Data type should be {@String} as {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
public static final int METADATA_UNTHETHERED_LEFT_CHARGING = 13; public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13;
/** /**
* Whether the right headset is charging * Whether the right headset is charging
* Data type should be {@String} as {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
public static final int METADATA_UNTHETHERED_RIGHT_CHARGING = 14; public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14;
/** /**
* Whether the headset charging case is charging * Whether the headset charging case is charging
* Data type should be {@String} as {@link Byte} array.
* @hide * @hide
*/ */
@SystemApi @SystemApi
public static final int METADATA_UNTHETHERED_CASE_CHARGING = 15; public static final int METADATA_UNTETHERED_CASE_CHARGING = 15;
/** /**
* URI to the enhanced settings UI slice, null or empty String means * URI to the enhanced settings UI slice
* the UI does not exist * Data type should be {@String} as {@link Byte} array, null means
* the UI does not exist.
* @hide * @hide
*/ */
@SystemApi @SystemApi
@@ -2243,21 +2261,21 @@ public final class BluetoothDevice implements Parcelable {
* {@link #BOND_NONE}. * {@link #BOND_NONE}.
* *
* @param key must be within the list of BluetoothDevice.METADATA_* * @param key must be within the list of BluetoothDevice.METADATA_*
* @param value the string data to set for key. Must be less than * @param value a byte array data to set for key. Must be less than
* {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length * {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length
* @return true on success, false on error * @return true on success, false on error
* @hide * @hide
*/ */
@SystemApi @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setMetadata(int key, String value) { public boolean setMetadata(int key, @NonNull byte[] value) {
final IBluetooth service = sService; final IBluetooth service = sService;
if (service == null) { if (service == null) {
Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata"); Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
return false; return false;
} }
if (value.length() > METADATA_MAX_LENGTH) { if (value.length > METADATA_MAX_LENGTH) {
throw new IllegalArgumentException("value length is " + value.length() throw new IllegalArgumentException("value length is " + value.length
+ ", should not over " + METADATA_MAX_LENGTH); + ", should not over " + METADATA_MAX_LENGTH);
} }
try { try {
@@ -2272,12 +2290,13 @@ public final class BluetoothDevice implements Parcelable {
* Get a keyed metadata for this {@link BluetoothDevice} as {@link String} * Get a keyed metadata for this {@link BluetoothDevice} as {@link String}
* *
* @param key must be within the list of BluetoothDevice.METADATA_* * @param key must be within the list of BluetoothDevice.METADATA_*
* @return Metadata of the key as string, null on error or not found * @return Metadata of the key as byte array, null on error or not found
* @hide * @hide
*/ */
@SystemApi @SystemApi
@Nullable
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public String getMetadata(int key) { public byte[] getMetadata(int key) {
final IBluetooth service = sService; final IBluetooth service = sService;
if (service == null) { if (service == null) {
Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata"); Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");