summaryrefslogtreecommitdiff
path: root/framework/java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/java')
-rw-r--r--framework/java/android/bluetooth/BluetoothAdapter.java39
-rwxr-xr-xframework/java/android/bluetooth/BluetoothClass.java2
-rw-r--r--framework/java/android/bluetooth/BluetoothDevice.java33
-rw-r--r--framework/java/android/bluetooth/BluetoothHapClient.java677
-rw-r--r--framework/java/android/bluetooth/BluetoothHapPresetInfo.java6
-rw-r--r--framework/java/android/bluetooth/BluetoothHeadset.java17
-rw-r--r--framework/java/android/bluetooth/BluetoothHeadsetClient.java215
-rw-r--r--framework/java/android/bluetooth/BluetoothLeAudioCodecConfig.java4
-rw-r--r--framework/java/android/bluetooth/BluetoothProfile.java5
-rw-r--r--framework/java/android/bluetooth/BluetoothStatusCodes.java2
-rw-r--r--framework/java/android/bluetooth/BluetoothUuid.java8
-rw-r--r--framework/java/android/bluetooth/OWNERS8
12 files changed, 571 insertions, 445 deletions
diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java
index 05c67f360a..dc7ffa6fd2 100644
--- a/framework/java/android/bluetooth/BluetoothAdapter.java
+++ b/framework/java/android/bluetooth/BluetoothAdapter.java
@@ -251,6 +251,8 @@ public final class BluetoothAdapter {
*
* @hide
*/
+ @SystemApi
+ @SuppressLint("ActionValue")
public static final String EXTRA_RFCOMM_LISTENER_ID =
"android.bluetooth.adapter.extra.RFCOMM_LISTENER_ID";
@@ -1137,9 +1139,7 @@ public final class BluetoothAdapter {
try {
final SynchronousResultReceiver<Integer> recv =
new SynchronousResultReceiver();
- if (mService != null) {
- mService.getState(recv);
- }
+ mService.getState(recv);
return recv.awaitResultNoInterrupt(getSyncTimeout())
.getValue(BluetoothAdapter.STATE_OFF);
} catch (TimeoutException e) {
@@ -1183,11 +1183,8 @@ public final class BluetoothAdapter {
mService.getState(recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(state);
}
- } catch (TimeoutException e) {
+ } catch (RemoteException | TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- e.rethrowFromSystemServer();
} finally {
mServiceLock.readLock().unlock();
}
@@ -1289,7 +1286,20 @@ public final class BluetoothAdapter {
* such as Airplane mode, or the adapter is already turned on.
*
* @return true to indicate adapter startup has begun, or false on immediate error
+ *
+ * @deprecated Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, applications
+ * are not allowed to enable/disable Bluetooth.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#TIRAMISU} or above, this API will always fail and return
+ * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#S}
+ * or below), they can continue to use this API.
+ * <p>
+ * Deprecation Exemptions:
+ * <ul>
+ * <li>Device Owner (DO), Profile Owner (PO) and system apps.
+ * </ul>
*/
+ @Deprecated
@RequiresLegacyBluetoothAdminPermission
@RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@@ -1329,7 +1339,20 @@ public final class BluetoothAdapter {
* such as the adapter already being turned off.
*
* @return true to indicate adapter shutdown has begun, or false on immediate error
+ *
+ * @deprecated Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, applications
+ * are not allowed to enable/disable Bluetooth.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#TIRAMISU} or above, this API will always fail and return
+ * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#S}
+ * or below), they can continue to use this API.
+ * <p>
+ * Deprecation Exemptions:
+ * <ul>
+ * <li>Device Owner (DO), Profile Owner (PO) and system apps.
+ * </ul>
*/
+ @Deprecated
@RequiresLegacyBluetoothAdminPermission
@RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@@ -3139,7 +3162,7 @@ public final class BluetoothAdapter {
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
@RfcommListenerResult
- public int closeRfcommServer(@NonNull UUID uuid) {
+ public int stopRfcommServer(@NonNull UUID uuid) {
try {
final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
mService.stopRfcommListener(new ParcelUuid(uuid), mAttributionSource, recv);
diff --git a/framework/java/android/bluetooth/BluetoothClass.java b/framework/java/android/bluetooth/BluetoothClass.java
index 699c80e5b6..fb13be4672 100755
--- a/framework/java/android/bluetooth/BluetoothClass.java
+++ b/framework/java/android/bluetooth/BluetoothClass.java
@@ -18,7 +18,6 @@ package android.bluetooth;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
@@ -307,7 +306,6 @@ public final class BluetoothClass implements Parcelable {
*
* @hide
*/
- @TestApi
public int getClassOfDevice() {
return mClass;
}
diff --git a/framework/java/android/bluetooth/BluetoothDevice.java b/framework/java/android/bluetooth/BluetoothDevice.java
index 2b335abc84..9caed4ccac 100644
--- a/framework/java/android/bluetooth/BluetoothDevice.java
+++ b/framework/java/android/bluetooth/BluetoothDevice.java
@@ -2545,39 +2545,6 @@ public final class BluetoothDevice implements Parcelable, Attributable {
return defaultValue;
}
- /**
- * Cancels pairing to this device
- *
- * @return true if pairing cancelled successfully, false otherwise
- *
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean cancelPairing() {
- if (DBG) log("cancelPairing()");
- final IBluetooth service = sService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot cancel pairing");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.cancelBondProcess(this, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
boolean isBluetoothEnabled() {
boolean ret = false;
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
diff --git a/framework/java/android/bluetooth/BluetoothHapClient.java b/framework/java/android/bluetooth/BluetoothHapClient.java
index 2b245bcb41..fd769d412b 100644
--- a/framework/java/android/bluetooth/BluetoothHapClient.java
+++ b/framework/java/android/bluetooth/BluetoothHapClient.java
@@ -25,6 +25,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.content.AttributionSource;
@@ -39,7 +40,9 @@ import com.android.modules.utils.SynchronousResultReceiver;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException;
@@ -58,6 +61,8 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
private static final boolean DBG = false;
private static final boolean VDBG = false;
+ private final Map<Callback, Executor> mCallbackExecutorMap = new HashMap<>();
+
private CloseGuard mCloseGuard;
/**
@@ -83,17 +88,6 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
@interface Status {}
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- PRESET_INFO_REASON_ALL_PRESET_INFO,
- PRESET_INFO_REASON_PRESET_INFO_UPDATE,
- PRESET_INFO_REASON_PRESET_DELETED,
- PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED,
- PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE,
- })
- @interface PresetInfoReason {}
-
/**
* Invoked to inform about HA device's currently active preset.
*
@@ -180,6 +174,87 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
void onSetPresetNameForGroupFailed(int hapGroupId, @Status int status);
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
+ private final IBluetoothHapClientCallback mCallback = new IBluetoothHapClientCallback.Stub() {
+ @Override
+ public void onActivePresetChanged(@NonNull BluetoothDevice device, int presetIndex) {
+ Attributable.setAttributionSource(device, mAttributionSource);
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(() -> callback.onActivePresetChanged(device, presetIndex));
+ }
+ }
+
+ @Override
+ public void onSelectActivePresetFailed(@NonNull BluetoothDevice device, int status) {
+ Attributable.setAttributionSource(device, mAttributionSource);
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(() -> callback.onSelectActivePresetFailed(device, status));
+ }
+ }
+
+ @Override
+ public void onSelectActivePresetForGroupFailed(int hapGroupId, int statusCode) {
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(
+ () -> callback.onSelectActivePresetForGroupFailed(hapGroupId, statusCode));
+ }
+ }
+
+ @Override
+ public void onPresetInfoChanged(@NonNull BluetoothDevice device,
+ @NonNull List<BluetoothHapPresetInfo> presetInfoList, int statusCode) {
+ Attributable.setAttributionSource(device, mAttributionSource);
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(
+ () -> callback.onPresetInfoChanged(device, presetInfoList, statusCode));
+ }
+ }
+
+ @Override
+ public void onHapFeaturesAvailable(@NonNull BluetoothDevice device, int hapFeatures) {
+ Attributable.setAttributionSource(device, mAttributionSource);
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(() -> callback.onHapFeaturesAvailable(device, hapFeatures));
+ }
+ }
+
+ @Override
+ public void onSetPresetNameFailed(@NonNull BluetoothDevice device, int status) {
+ Attributable.setAttributionSource(device, mAttributionSource);
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(() -> callback.onSetPresetNameFailed(device, status));
+ }
+ }
+
+ @Override
+ public void onSetPresetNameForGroupFailed(int hapGroupId, int status) {
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(() -> callback.onSetPresetNameForGroupFailed(hapGroupId, status));
+ }
+ }
+ };
+
/**
* Intent used to broadcast the change in connection state of the Hearing Access Profile Client
* service. Please note that in the binaural case, there will be two different LE devices for
@@ -229,235 +304,12 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
"android.bluetooth.action.HAP_DEVICE_AVAILABLE";
/**
- * Intent used to broadcast HA device's feature set.
- *
- * <p>This intent will have 2 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_HAP_FEATURES}- The feature set integer with these possible bit numbers
- * set: {@link #FEATURE_BIT_NUM_TYPE_MONAURAL}, {@link #FEATURE_BIT_NUM_TYPE_BANDED},
- * {@link #FEATURE_BIT_NUM_SYNCHRONIZATED_PRESETS},
- * {@link #FEATURE_BIT_NUM_INDEPENDENT_PRESETS}, {@link #FEATURE_BIT_NUM_DYNAMIC_PRESETS},
- * {@link #FEATURE_BIT_NUM_WRITABLE_PRESETS}.</li>
- * </ul>
- *
- * @hide
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HAP_ON_DEVICE_FEATURES =
- "android.bluetooth.action.HAP_ON_DEVICE_FEATURES";
-
- /**
- * Intent used to broadcast the change of a HA device's active preset.
- *
- * <p>This intent will have 2 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_HAP_PRESET_INDEX}- The currently active preset.</li>
- * </ul>
- *
- * @hide
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HAP_ON_ACTIVE_PRESET =
- "android.bluetooth.action.HAP_ON_ACTIVE_PRESET";
-
- /**
- * Intent used to broadcast the result of a failed preset change attempt.
- *
- * <p>This intent will have 2 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_HAP_STATUS_CODE}- Failure reason.</li>
- * </ul>
- *
- * <p>{@link #EXTRA_HAP_STATUS_CODE} can be any of {@link #STATUS_INVALID_PRESET_INDEX},
- * {@link #STATUS_OPERATION_NOT_POSSIBLE},{@link #STATUS_OPERATION_NOT_SUPPORTED}.
- *
- * @hide
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HAP_ON_ACTIVE_PRESET_SELECT_ERROR =
- "android.bluetooth.action.HAP_ON_ACTIVE_PRESET_SELECT_ERROR";
-
- /**
- * Intent used to broadcast preset name change.
- *
- * <p>This intent will have 4 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_HAP_PRESET_INFO}- List of preset informations </li>
- * <li> {@link #EXTRA_HAP_PRESET_INFO_REASON}- Why this preset info notification was sent </li>
- * notifications or the user should expect more to come. </li>
- * </ul>
- *
- * @hide
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HAP_ON_PRESET_INFO =
- "android.bluetooth.action.HAP_ON_PRESET_INFO";
-
- /**
- * Intent used to broadcast result of a failed rename attempt.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_HAP_PRESET_INDEX}- The currently active preset.</li>
- * <li> {@link #EXTRA_HAP_STATUS_CODE}- Failure reason code.</li>
- * </ul>
- *
- * <p>{@link #EXTRA_HAP_STATUS_CODE} can be any of {@link #STATUS_SET_NAME_NOT_ALLOWED},
- * {@link #STATUS_INVALID_PRESET_INDEX}, {@link #STATUS_INVALID_PRESET_NAME_LENGTH}.
- *
- * @hide
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HAP_ON_PRESET_NAME_SET_ERROR =
- "android.bluetooth.action.HAP_ON_PRESET_NAME_SET_ERROR";
-
- /**
- * Intent used to broadcast the result of a failed name get attempt.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_HAP_PRESET_INDEX}- The currently active preset.</li>
- * <li> {@link #EXTRA_HAP_STATUS_CODE}- Failure reason code.</li>
- * </ul>
- *
- * <p>{@link #EXTRA_HAP_STATUS_CODE} can be any of {@link #STATUS_INVALID_PRESET_INDEX},
- * {@link #STATUS_OPERATION_NOT_POSSIBLE}.
- *
- * @hide
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HAP_ON_PRESET_INFO_GET_ERROR =
- "android.bluetooth.action.HAP_ON_PRESET_INFO_GET_ERROR";
-
- /**
* Contains a list of all available presets
* @hide
*/
public static final String EXTRA_HAP_FEATURES = "android.bluetooth.extra.HAP_FEATURES";
/**
- * Contains a preset identifier
- * @hide
- */
- public static final String EXTRA_HAP_PRESET_INDEX = "android.bluetooth.extra.HAP_PRESET_INDEX";
-
- /**
- * Used to report failure reasons.
- * @hide
- */
- public static final String EXTRA_HAP_STATUS_CODE = "android.bluetooth.extra.HAP_STATUS_CODE";
-
- /**
- * Used by group events.
- * @hide
- */
- public static final String EXTRA_HAP_GROUP_ID = "android.bluetooth.extra.HAP_GROUP_ID";
-
- /**
- * Preset Info reason.
- * Possible values:
- * {@link #PRESET_INFO_REASON_ALL_PRESET_INFO} or
- * {@link #PRESET_INFO_REASON_PRESET_INFO_UPDATE} or
- * {@link #PRESET_INFO_REASON_PRESET_DELETED} or
- * {@link #PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED} or
- * {@link #PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE}
- * @hide
- */
- public static final String EXTRA_HAP_PRESET_INFO_REASON =
- "android.bluetooth.extra.HAP_PRESET_INFO_REASON";
-
- /**
- * Preset Info.
- * @hide
- */
- public static final String EXTRA_HAP_PRESET_INFO = "android.bluetooth.extra.HAP_PRESET_INFO";
-
- /**
- * Preset name change failure due to preset being read-only.
- * @hide
- */
- public static final int STATUS_SET_NAME_NOT_ALLOWED =
- IBluetoothHapClient.STATUS_SET_NAME_NOT_ALLOWED;
-
- /**
- * Means that the requested operation is not supported by the HA device.
- *
- * <p> It could mean that the requested name change is not supported on
- * a given preset or the device does not support presets at all.
- * @hide
- */
- public static final int STATUS_OPERATION_NOT_SUPPORTED =
- IBluetoothHapClient.STATUS_OPERATION_NOT_SUPPORTED;
-
- /**
- * Usually means a temporary denial of certain operation. Peer device may report this
- * status due to various implementation specific reasons. It's different than
- * the {@link #STATUS_OPERATION_NOT_SUPPORTED} which represents more of a
- * permanent inability to perform some of the operations.
- * @hide
- */
- public static final int STATUS_OPERATION_NOT_POSSIBLE =
- IBluetoothHapClient.STATUS_OPERATION_NOT_POSSIBLE;
-
- /**
- * Used when preset name change failed due to the passed name parameter being to long.
- * @hide
- */
- public static final int STATUS_INVALID_PRESET_NAME_LENGTH =
- IBluetoothHapClient.STATUS_INVALID_PRESET_NAME_LENGTH;
-
- /**
- * Group operations are not supported.
- * @hide
- */
- public static final int STATUS_GROUP_OPERATION_NOT_SUPPORTED =
- IBluetoothHapClient.STATUS_GROUP_OPERATION_NOT_SUPPORTED;
-
- /**
- * Procedure is already in progress.
- * @hide
- */
- public static final int STATUS_PROCEDURE_ALREADY_IN_PROGRESS =
- IBluetoothHapClient.STATUS_PROCEDURE_ALREADY_IN_PROGRESS;
-
- /**
- * Invalid preset index input parameter used in one of the API calls.
- * @hide
- */
- public static final int STATUS_INVALID_PRESET_INDEX =
- IBluetoothHapClient.STATUS_INVALID_PRESET_INDEX;
-
- /**
* Represets an invalid index value. This is usually value returned in a currently
* active preset request for a device which is not connected. This value shouldn't be used
* in the API calls.
@@ -507,48 +359,6 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
public static final int FEATURE_BIT_NUM_WRITABLE_PRESETS =
IBluetoothHapClient.FEATURE_BIT_NUM_WRITABLE_PRESETS;
- /**
- * Preset Info notification reason.
- * @hide
- */
- public static final int PRESET_INFO_REASON_ALL_PRESET_INFO =
- IBluetoothHapClient.PRESET_INFO_REASON_ALL_PRESET_INFO;
-
- /**
- * Preset Info notification reason.
- * @hide
- */
- public static final int PRESET_INFO_REASON_PRESET_INFO_UPDATE =
- IBluetoothHapClient.PRESET_INFO_REASON_PRESET_INFO_UPDATE;
-
- /**
- * Preset Info notification reason.
- * @hide
- */
- public static final int PRESET_INFO_REASON_PRESET_DELETED =
- IBluetoothHapClient.PRESET_INFO_REASON_PRESET_DELETED;
-
- /**
- * Preset Info notification reason.
- * @hide
- */
- public static final int PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED =
- IBluetoothHapClient.PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED;
-
- /**
- * Preset Info notification reason.
- * @hide
- */
- public static final int PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE =
- IBluetoothHapClient.PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE;
-
- /**
- * Represents invalid group identifier. It's returned when user requests a group identifier
- * for a device which is not part of any group. This value shouldn't be used in the API calls.
- * @hide
- */
- public static final int HAP_GROUP_UNAVAILABLE = IBluetoothHapClient.GROUP_ID_UNAVAILABLE;
-
private final BluetoothAdapter mAdapter;
private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothHapClient> mProfileConnector =
@@ -560,6 +370,35 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
}
};
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
+ private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (up) {
+ // re-register the service-to-app callback
+ synchronized (mCallbackExecutorMap) {
+ if (mCallbackExecutorMap.isEmpty()) return;
+
+ try {
+ final IBluetoothHapClient service = getService();
+ if (service != null) {
+ final SynchronousResultReceiver<Integer> recv =
+ new SynchronousResultReceiver();
+ service.registerCallback(mCallback, mAttributionSource, recv);
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
+ }
+ } catch (TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n"
+ + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+ }
+ };
+
/**
* Create a BluetoothHapClient proxy object for interacting with the local
* Bluetooth Hearing Access Profile (HAP) client.
@@ -568,6 +407,16 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
mAdapter = BluetoothAdapter.getDefaultAdapter();
mAttributionSource = mAdapter.getAttributionSource();
mProfileConnector.connect(context, listener);
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
mCloseGuard = new CloseGuard();
mCloseGuard.open("close");
}
@@ -586,6 +435,17 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
* @hide
*/
public void close() {
+ if (VDBG) log("close()");
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
mProfileConnector.disconnect();
}
@@ -621,8 +481,36 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
}
+ if (!isEnabled()) {
+ throw new IllegalStateException("service not enabled");
+ }
+
if (DBG) log("registerCallback");
- throw new UnsupportedOperationException("Not Implemented");
+
+ synchronized (mCallbackExecutorMap) {
+ // If the callback map is empty, we register the service-to-app callback
+ if (mCallbackExecutorMap.isEmpty()) {
+ try {
+ final IBluetoothHapClient service = getService();
+ if (service != null) {
+ final SynchronousResultReceiver<Integer> recv =
+ new SynchronousResultReceiver();
+ service.registerCallback(mCallback, mAttributionSource, recv);
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
+ }
+ } catch (IllegalStateException | TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ // Adds the passed in callback to our map of callbacks to executors
+ if (mCallbackExecutorMap.containsKey(callback)) {
+ throw new IllegalArgumentException("This callback has already been registered");
+ }
+ mCallbackExecutorMap.put(callback, executor);
+ }
}
/**
@@ -646,8 +534,30 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
}
+
if (DBG) log("unregisterCallback");
- throw new UnsupportedOperationException("Not Implemented");
+
+ synchronized (mCallbackExecutorMap) {
+ if (mCallbackExecutorMap.remove(callback) != null) {
+ throw new IllegalArgumentException("This callback has not been registered");
+ }
+ }
+
+ // If the callback map is empty, we unregister the service-to-app callback
+ if (mCallbackExecutorMap.isEmpty()) {
+ try {
+ final IBluetoothHapClient service = getService();
+ if (service != null) {
+ final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
+ service.unregisterCallback(mCallback, mAttributionSource, recv);
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
+ }
+ } catch (TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
/**
@@ -683,8 +593,10 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -719,8 +631,10 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
service.getConnectionPolicy(device, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -748,9 +662,13 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
try {
final SynchronousResultReceiver<List> recv = new SynchronousResultReceiver();
service.getConnectedDevices(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ return Attributable.setAttributionSource(
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
+ mAttributionSource);
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -779,9 +697,13 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
try {
final SynchronousResultReceiver<List> recv = new SynchronousResultReceiver();
service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ return Attributable.setAttributionSource(
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
+ mAttributionSource);
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -811,8 +733,10 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
service.getConnectionState(device, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -828,12 +752,11 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
* require individual device calls.
*
* <p>Note that some binaural HA devices may not support group operations,
- * therefore are not considered a valid HAP group. In such case the
- * {@link #HAP_GROUP_UNAVAILABLE} is returned even when such
- * device is a valid Le Audio Coordinated Set member.
+ * therefore are not considered a valid HAP group. In such case -1 is returned
+ * even if such device is a valid Le Audio Coordinated Set member.
*
* @param device
- * @return valid group identifier or {@link #HAP_GROUP_UNAVAILABLE}
+ * @return valid group identifier or -1
* @hide
*/
@RequiresBluetoothConnectPermission
@@ -843,7 +766,7 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public int getHapGroup(@NonNull BluetoothDevice device) {
final IBluetoothHapClient service = getService();
- final int defaultValue = HAP_GROUP_UNAVAILABLE;
+ final int defaultValue = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
@@ -852,8 +775,10 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
service.getHapGroup(device, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -878,14 +803,15 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled() && isValidDevice(device)) {
- // TODO(b/216639668)
- // try {
- // final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- // service.getActivePresetIndex(device, mAttributionSource, recv);
- // return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- // } catch (RemoteException | TimeoutException e) {
- // Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- // }
+ try {
+ final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
+ service.getActivePresetIndex(device, mAttributionSource, recv);
+ return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+ } catch (TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
return defaultValue;
}
@@ -905,8 +831,25 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
android.Manifest.permission.BLUETOOTH_PRIVILEGED
})
public @Nullable BluetoothHapPresetInfo getActivePresetInfo(@NonNull BluetoothDevice device) {
- // TODO(b/216639668)
- return null;
+ final IBluetoothHapClient service = getService();
+ final BluetoothHapPresetInfo defaultValue = null;
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) log(Log.getStackTraceString(new Throwable()));
+ } else if (isEnabled() && isValidDevice(device)) {
+ try {
+ final SynchronousResultReceiver<BluetoothHapPresetInfo> recv =
+ new SynchronousResultReceiver();
+ service.getActivePresetInfo(device, mAttributionSource, recv);
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+ } catch (TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ return defaultValue;
}
/**
@@ -928,18 +871,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void selectPreset(@NonNull BluetoothDevice device, int presetIndex) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled() && isValidDevice(device)) {
try {
- // TODO(b/216639668)
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.selectActivePreset(device, presetIndex, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.selectPreset(device, presetIndex, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -968,18 +907,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void selectPresetForGroup(int groupId, int presetIndex) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled()) {
try {
- // TODO(b/216639668)
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.groupSelectActivePreset(groupId, presetIndex, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.selectPresetForGroup(groupId, presetIndex, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1000,18 +935,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void switchToNextPreset(@NonNull BluetoothDevice device) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled() && isValidDevice(device)) {
try {
- // TODO(b/216639668)
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.nextActivePreset(device, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.switchToNextPreset(device, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1034,18 +965,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void switchToNextPresetForGroup(int groupId) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled()) {
try {
- // TODO(b/216639668)
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.groupNextActivePreset(groupId, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.switchToNextPresetForGroup(groupId, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1066,18 +993,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void switchToPreviousPreset(@NonNull BluetoothDevice device) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled() && isValidDevice(device)) {
try {
- // TODO(b/216639668)
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.previousActivePreset(device, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.switchToPreviousPreset(device, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1100,18 +1023,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void switchToPreviousPresetForGroup(int groupId) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled()) {
try {
- // TODO(b/216639668)
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.groupPreviousActivePreset(groupId, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.switchToPreviousPresetForGroup(groupId, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1129,24 +1048,26 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED
})
- public @NonNull BluetoothHapPresetInfo getPresetInfo(@NonNull BluetoothDevice device,
+ public @Nullable BluetoothHapPresetInfo getPresetInfo(@NonNull BluetoothDevice device,
int presetIndex) {
final IBluetoothHapClient service = getService();
- final BluetoothHapPresetInfo.Builder builder = new BluetoothHapPresetInfo.Builder();
+ final BluetoothHapPresetInfo defaultValue = null;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled() && isValidDevice(device)) {
- // TODO(b/216639668)
- // try {
- // final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- // service.getPresetInfo(device, presetIndex, mAttributionSource, recv);
- // return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(builder);
- // } catch (RemoteException | TimeoutException e) {
- // Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- // }
+ try {
+ final SynchronousResultReceiver<BluetoothHapPresetInfo> recv =
+ new SynchronousResultReceiver();
+ service.getPresetInfo(device, presetIndex, mAttributionSource, recv);
+ return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+ } catch (TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
- return builder.build();
+ return defaultValue;
}
/**
@@ -1169,14 +1090,16 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled() && isValidDevice(device)) {
- // TODO(b/216639668)
- // try {
- // final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- // service.getAllPresetsInfo(device, mAttributionSource, recv);
- // return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- // } catch (RemoteException | TimeoutException e) {
- // Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- // }
+ try {
+ final SynchronousResultReceiver<List<BluetoothHapPresetInfo>> recv =
+ new SynchronousResultReceiver();
+ service.getAllPresetInfo(device, mAttributionSource, recv);
+ return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+ } catch (TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
return defaultValue;
}
@@ -1193,19 +1116,21 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED
})
- public boolean getFeatures(@NonNull BluetoothDevice device) {
+ public int getFeatures(@NonNull BluetoothDevice device) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
+ final int defaultValue = 0x00;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled() && isValidDevice(device)) {
try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
+ final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
service.getFeatures(device, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -1235,18 +1160,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
public void setPresetName(@NonNull BluetoothDevice device, int presetIndex,
@NonNull String name) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled() && isValidDevice(device)) {
try {
- // TODO(b/216639668)
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setPresetName(device, presetIndex, name, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.setPresetName(device, presetIndex, name, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1274,18 +1195,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void setPresetNameForGroup(int groupId, int presetIndex, @NonNull String name) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled()) {
try {
- // TODO(b/216639668)
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.groupSetPresetName(groupId, presetIndex, name, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.setPresetNameForGroup(groupId, presetIndex, name, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/framework/java/android/bluetooth/BluetoothHapPresetInfo.java b/framework/java/android/bluetooth/BluetoothHapPresetInfo.java
index b8c09ccbb7..70fb54a3bb 100644
--- a/framework/java/android/bluetooth/BluetoothHapPresetInfo.java
+++ b/framework/java/android/bluetooth/BluetoothHapPresetInfo.java
@@ -29,7 +29,7 @@ import android.os.Parcelable;
@SystemApi
public final class BluetoothHapPresetInfo implements Parcelable {
private int mPresetIndex;
- private String mPresetName;
+ private String mPresetName = "";
private boolean mIsWritable;
private boolean mIsAvailable;
@@ -165,7 +165,7 @@ public final class BluetoothHapPresetInfo implements Parcelable {
* @param isWritable whether preset is writable
* @return the same Builder instance
*/
- public @NonNull Builder setWritable(@NonNull boolean isWritable) {
+ public @NonNull Builder setWritable(boolean isWritable) {
mIsWritable = isWritable;
return this;
}
@@ -176,7 +176,7 @@ public final class BluetoothHapPresetInfo implements Parcelable {
* @param isAvailable whether preset is currently available to select
* @return the same Builder instance
*/
- public @NonNull Builder setAvailable(@NonNull boolean isAvailable) {
+ public @NonNull Builder setAvailable(boolean isAvailable) {
mIsAvailable = isAvailable;
return this;
}
diff --git a/framework/java/android/bluetooth/BluetoothHeadset.java b/framework/java/android/bluetooth/BluetoothHeadset.java
index 8a037a97c0..4ff224d21a 100644
--- a/framework/java/android/bluetooth/BluetoothHeadset.java
+++ b/framework/java/android/bluetooth/BluetoothHeadset.java
@@ -1005,10 +1005,21 @@ public final class BluetoothHeadset implements BluetoothProfile {
BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
BluetoothStatusCodes.ERROR_TIMEOUT,
+ BluetoothStatusCodes.ERROR_UNKNOWN,
+ })
+ public @interface SetAudioRouteAllowedReturnValues {}
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
BluetoothStatusCodes.ALLOWED,
BluetoothStatusCodes.NOT_ALLOWED,
+ BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
+ BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
+ BluetoothStatusCodes.ERROR_TIMEOUT,
+ BluetoothStatusCodes.ERROR_UNKNOWN,
})
- public @interface AudioRouteAllowedReturnValues {}
+ public @interface GetAudioRouteAllowedReturnValues {}
/**
* Sets whether audio routing is allowed. When set to {@code false}, the AG
@@ -1029,7 +1040,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
- public @AudioRouteAllowedReturnValues int setAudioRouteAllowed(boolean allowed) {
+ public @SetAudioRouteAllowedReturnValues int setAudioRouteAllowed(boolean allowed) {
if (VDBG) log("setAudioRouteAllowed");
final IBluetoothHeadset service = mService;
if (service == null) {
@@ -1068,7 +1079,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
- public @AudioRouteAllowedReturnValues int getAudioRouteAllowed() {
+ public @GetAudioRouteAllowedReturnValues int getAudioRouteAllowed() {
if (VDBG) log("getAudioRouteAllowed");
final IBluetoothHeadset service = mService;
if (service == null) {
diff --git a/framework/java/android/bluetooth/BluetoothHeadsetClient.java b/framework/java/android/bluetooth/BluetoothHeadsetClient.java
index 87bd76114b..f1402d485d 100644
--- a/framework/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/framework/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -18,6 +18,7 @@ package android.bluetooth;
import static android.bluetooth.BluetoothUtils.getSyncTimeout;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -31,6 +32,8 @@ import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.util.CloseGuard;
import android.util.Log;
@@ -1615,6 +1618,218 @@ public final class BluetoothHeadsetClient implements BluetoothProfile, AutoClose
}
return defaultValue;
}
+
+ /**
+ * A class that contains the network service info provided by the HFP Client profile
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final class NetworkServiceState implements Parcelable {
+ /** The device associated with this service state */
+ private final BluetoothDevice mDevice;
+
+ /** True if there is service available, False otherwise */
+ private final boolean mIsServiceAvailable;
+
+ /** The name of the operator associated with the remote device's current network */
+ private final String mOperatorName;
+
+ /**
+ * The general signal strength
+ * (0 - Unknown, 1 - Poor, 2 - Fair, 3 - Good, 4 - Great, 5 - Excellent)
+ */
+ private final int mSignalStrength;
+
+ /** True if we are network roaming, False otherwise */
+ private final boolean mIsRoaming;
+
+ /**
+ * Create a NetworkServiceState Object
+ *
+ * @param device The device associated with this network signal state
+ * @param isServiceAvailable True if there is service available, False otherwise
+ * @param operatorName The name of the operator associated with the remote device's current
+ * network. Use Null if the value is unknown
+ * @param signalStrength The general signal strength
+ * @param isRoaming True if we are network roaming, False otherwise
+ *
+ * @hide
+ */
+ public NetworkServiceState(BluetoothDevice device, boolean isServiceAvailable,
+ String operatorName, int signalStrength, boolean isRoaming) {
+ mDevice = device;
+ mIsServiceAvailable = isServiceAvailable;
+ mOperatorName = operatorName;
+ mSignalStrength = signalStrength;
+ mIsRoaming = isRoaming;
+ }
+
+ /**
+ * Get the device associated with this network service state
+ *
+ * @return a BluetoothDevice associated with this state
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull BluetoothDevice getDevice() {
+ return mDevice;
+ }
+
+ /**
+ * Get the network service availablility state
+ *
+ * @return True if there is service available, False otherwise
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isServiceAvailable() {
+ return mIsServiceAvailable;
+ }
+
+ /**
+ * Get the network operator name
+ *
+ * @return A string representing the name of the operator the remote device is on, or null
+ * if unknown.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @Nullable String getOperatorName() {
+ return mOperatorName;
+ }
+
+ /**
+ * Get the network's general signal strength
+ *
+ * @return The general signal strength (0 - None, 1 - Poor, 2 - Fair, 3 - Good,
+ * 4 - Great, 5 - Excellent)
+ *
+ * @hide
+ */
+ @SystemApi
+ public int getSignalStrength() {
+ return mSignalStrength;
+ }
+
+ /**
+ * Get the network service roaming status
+ *
+ * * @return True if we are network roaming, False otherwise
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isRoaming() {
+ return mIsRoaming;
+ }
+
+ /**
+ * {@link Parcelable.Creator} interface implementation.
+ */
+ public static final @NonNull Parcelable.Creator<NetworkServiceState> CREATOR =
+ new Parcelable.Creator<NetworkServiceState>() {
+ public NetworkServiceState createFromParcel(Parcel in) {
+ return new NetworkServiceState((BluetoothDevice) in.readParcelable(null),
+ in.readInt() == 1, in.readString(), in.readInt(), in.readInt() == 1);
+ }
+
+ public @NonNull NetworkServiceState[] newArray(int size) {
+ return new NetworkServiceState[size];
+ }
+ };
+
+ /**
+ * @hide
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeParcelable(mDevice, 0);
+ out.writeInt(mIsServiceAvailable ? 1 : 0);
+ out.writeString(mOperatorName);
+ out.writeInt(mSignalStrength);
+ out.writeInt(mIsRoaming ? 1 : 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+ }
+
+ /**
+ * Intent used to broadcast the change in network service state of an HFP Client device
+ *
+ * <p>This intent will have 2 extras:
+ * <ul>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * <li> {@link EXTRA_NETWORK_SERVICE_STATE} - A {@link NetworkServiceState} object. </li>
+ * </ul>
+ *
+ * @hide
+ */
+ @SuppressLint("ActionValue")
+ @SystemApi
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_NETWORK_SERVICE_STATE_CHANGED =
+ "android.bluetooth.headsetclient.profile.action.NETWORK_SERVICE_STATE_CHANGED";
+
+ /**
+ * Extra for the network service state changed intent.
+ *
+ * This extra represents the current network service state of a connected Bluetooth device.
+ *
+ * @hide
+ */
+ @SuppressLint("ActionValue")
+ @SystemApi
+ public static final String EXTRA_NETWORK_SERVICE_STATE =
+ "android.bluetooth.headsetclient.extra.EXTRA_NETWORK_SERVICE_STATE";
+
+ /**
+ * Get the network service state for a device
+ *
+ * @param device The {@link BluetoothDevice} you want the network service state for
+ * @return A {@link NetworkServiceState} representing the network service state of the device,
+ * or null if the device is not connected
+ * @hide
+ */
+ @SystemApi
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
+ public @Nullable NetworkServiceState getNetworkServiceState(@NonNull BluetoothDevice device) {
+ if (device == null) {
+ return null;
+ }
+
+ Bundle agEvents = getCurrentAgEvents(device);
+ if (agEvents == null) {
+ return null;
+ }
+
+ boolean isServiceAvailable = (agEvents.getInt(EXTRA_NETWORK_STATUS, 0) == 1);
+ int signalStrength = agEvents.getInt(EXTRA_NETWORK_SIGNAL_STRENGTH, 0);
+ String operatorName = agEvents.getString(EXTRA_OPERATOR_NAME, null);
+ boolean isRoaming = (agEvents.getInt(EXTRA_NETWORK_ROAMING, 0) == 1);
+
+ return new NetworkServiceState(device, isServiceAvailable, operatorName, signalStrength,
+ isRoaming);
+ }
+
private boolean isEnabled() {
return mAdapter.getState() == BluetoothAdapter.STATE_ON;
}
diff --git a/framework/java/android/bluetooth/BluetoothLeAudioCodecConfig.java b/framework/java/android/bluetooth/BluetoothLeAudioCodecConfig.java
index e3f691a66a..8377c2c7d2 100644
--- a/framework/java/android/bluetooth/BluetoothLeAudioCodecConfig.java
+++ b/framework/java/android/bluetooth/BluetoothLeAudioCodecConfig.java
@@ -336,14 +336,14 @@ public final class BluetoothLeAudioCodecConfig implements Parcelable {
/**
* Returns the frame duration.
*/
- public @ChannelMode int getFrameDuration() {
+ public @FrameDuration int getFrameDuration() {
return mFrameDuration;
}
/**
* Returns the octets per frame
*/
- public @ChannelMode int getOctetsPerFrame() {
+ public int getOctetsPerFrame() {
return mOctetsPerFrame;
}
diff --git a/framework/java/android/bluetooth/BluetoothProfile.java b/framework/java/android/bluetooth/BluetoothProfile.java
index 86606d2077..ff95269c30 100644
--- a/framework/java/android/bluetooth/BluetoothProfile.java
+++ b/framework/java/android/bluetooth/BluetoothProfile.java
@@ -19,7 +19,6 @@ package android.bluetooth;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresNoPermission;
-import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -457,7 +456,7 @@ public interface BluetoothProfile {
*/
@SystemApi
@NonNull
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresNoPermission
static String getConnectionStateName(int connectionState) {
switch (connectionState) {
case STATE_DISCONNECTED:
@@ -482,7 +481,7 @@ public interface BluetoothProfile {
*/
@SystemApi
@NonNull
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresNoPermission
static String getProfileName(int profile) {
switch(profile) {
case HEADSET:
diff --git a/framework/java/android/bluetooth/BluetoothStatusCodes.java b/framework/java/android/bluetooth/BluetoothStatusCodes.java
index 8825c3e71b..ebaace621b 100644
--- a/framework/java/android/bluetooth/BluetoothStatusCodes.java
+++ b/framework/java/android/bluetooth/BluetoothStatusCodes.java
@@ -227,7 +227,7 @@ public final class BluetoothStatusCodes {
* @hide
*/
@SystemApi
- public static final int ERROR_REMOTE_OPERATION_NOT_SUPPORTED = 24;
+ public static final int ERROR_REMOTE_OPERATION_NOT_SUPPORTED = 27;
/**
* A GATT writeCharacteristic request is not permitted on the remote device.
diff --git a/framework/java/android/bluetooth/BluetoothUuid.java b/framework/java/android/bluetooth/BluetoothUuid.java
index 7c9a076270..85c16f1288 100644
--- a/framework/java/android/bluetooth/BluetoothUuid.java
+++ b/framework/java/android/bluetooth/BluetoothUuid.java
@@ -158,9 +158,8 @@ public final class BluetoothUuid {
/** @hide */
@NonNull
@SystemApi
- /* FIXME: Not known yet, using a placeholder instead. */
public static final ParcelUuid HAS =
- ParcelUuid.fromString("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE");
+ ParcelUuid.fromString("00001854-0000-1000-8000-00805F9B34FB");
/** @hide */
@NonNull
@SystemApi
@@ -199,6 +198,11 @@ public final class BluetoothUuid {
/** @hide */
@NonNull
@SystemApi
+ public static final ParcelUuid BASS =
+ ParcelUuid.fromString("0000184F-0000-1000-8000-00805F9B34FB");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
diff --git a/framework/java/android/bluetooth/OWNERS b/framework/java/android/bluetooth/OWNERS
deleted file mode 100644
index bf15cf08bd..0000000000
--- a/framework/java/android/bluetooth/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-set noparent
-
-# Bug component: 27441
-
-rahulsabnis@google.com
-sattiraju@google.com
-siyuanh@google.com
-zachoverflow@google.com