LE Audio: Expose more system APIs

* Expose two intentss:
  * ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED
  * ACTION_LE_AUDIO_GROUP_NODE_STATUS_CHANGED
  * Settings and Telecom are interested in the group node status
    information, therefore lets expose the API as a SystemApi
* Reduce scope of HAP connection state API to system API
* Expose more system APIs for HAP client
  * To select different hearing presets
  * To get notified about changes in hearing presets
  * To get all available hearing presets
* Expose more system APIs for CSIP
  * To make error codes more visible for the API caller
* Expose GROUP_ID_INVALID to public API for getGroupId()

Bug: 150670922
Test: atest BluetoothInstrumentationTests
Tag: #feature
Sponsor: siyuanh@
Ignore-AOSP-First: earlier change merged on internal
Change-Id: If87e0863f23b989632603ac1253e4a77bfff028d
diff --git a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java
index 2e3614a..dec6db2 100644
--- a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java
+++ b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java
@@ -18,7 +18,6 @@
 package com.android.bluetooth.csip;
 
 import static android.Manifest.permission.BLUETOOTH_CONNECT;
-import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
 
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
@@ -26,6 +25,7 @@
 import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetoothCsipSetCoordinator;
 import android.bluetooth.IBluetoothCsipSetCoordinatorCallback;
@@ -488,7 +488,8 @@
             if (mLocks.containsKey(groupId)) {
                 try {
                     callback.onGroupLockSet(groupId,
-                            BluetoothCsipSetCoordinator.GROUP_LOCK_FAILED_LOCKED_BY_OTHER, true);
+                            BluetoothStatusCodes.ERROR_CSIP_GROUP_LOCKED_BY_OTHER,
+                            true);
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
                 }
@@ -615,6 +616,25 @@
         }
     }
 
+    int getApiStatusCode(int nativeResult) {
+        switch (nativeResult) {
+            case IBluetoothCsipSetCoordinator.CSIS_GROUP_LOCK_SUCCESS:
+                return BluetoothStatusCodes.SUCCESS;
+            case IBluetoothCsipSetCoordinator.CSIS_GROUP_LOCK_FAILED_INVALID_GROUP:
+                return BluetoothStatusCodes.ERROR_CSIP_INVALID_GROUP_ID;
+            case IBluetoothCsipSetCoordinator.CSIS_GROUP_LOCK_FAILED_GROUP_NOT_CONNECTED:
+                return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED;
+            case IBluetoothCsipSetCoordinator.CSIS_GROUP_LOCK_FAILED_LOCKED_BY_OTHER:
+                return BluetoothStatusCodes.ERROR_CSIP_GROUP_LOCKED_BY_OTHER;
+            case IBluetoothCsipSetCoordinator.CSIS_LOCKED_GROUP_MEMBER_LOST:
+                return BluetoothStatusCodes.ERROR_CSIP_LOCKED_GROUP_MEMBER_LOST;
+            case IBluetoothCsipSetCoordinator.CSIS_GROUP_LOCK_FAILED_OTHER_REASON:
+            default:
+                Log.e(TAG, " Unknown status code: " + nativeResult);
+                return BluetoothStatusCodes.ERROR_UNKNOWN;
+        }
+    }
+
     void handleGroupLockChanged(int groupId, int status, boolean isLocked) {
         synchronized (mLocks) {
             if (!mLocks.containsKey(groupId)) {
@@ -623,7 +643,7 @@
 
             IBluetoothCsipSetCoordinatorLockCallback cb = mLocks.get(groupId).second;
             try {
-                cb.onGroupLockSet(groupId, status, isLocked);
+                cb.onGroupLockSet(groupId, getApiStatusCode(status), isLocked);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
diff --git a/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java
index dd34055..5adc336 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java
@@ -260,11 +260,12 @@
                 .when(mCsipSetCoordinatorNativeInterface)
                 .onGroupLockChanged(anyInt(), anyBoolean(), anyInt());
         mCsipSetCoordinatorNativeInterface.onGroupLockChanged(
-                group, true, BluetoothCsipSetCoordinator.GROUP_LOCK_SUCCESS);
+                group, true, IBluetoothCsipSetCoordinator.CSIS_GROUP_LOCK_SUCCESS);
 
         try {
             verify(mCsipSetCoordinatorLockCallback, times(1))
-                    .onGroupLockSet(group, BluetoothCsipSetCoordinator.GROUP_LOCK_SUCCESS, true);
+                    .onGroupLockSet(group, BluetoothStatusCodes.SUCCESS,
+                        true);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -273,11 +274,12 @@
         verify(mCsipSetCoordinatorNativeInterface, times(1)).groupLockSet(eq(group), eq(false));
 
         mCsipSetCoordinatorNativeInterface.onGroupLockChanged(
-                group, false, BluetoothCsipSetCoordinator.GROUP_LOCK_SUCCESS);
+                group, false, IBluetoothCsipSetCoordinator.CSIS_GROUP_LOCK_SUCCESS);
 
         try {
             verify(mCsipSetCoordinatorLockCallback, times(1))
-                    .onGroupLockSet(group, BluetoothCsipSetCoordinator.GROUP_LOCK_SUCCESS, false);
+                    .onGroupLockSet(group, BluetoothStatusCodes.SUCCESS,
+                        false);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -305,7 +307,7 @@
         try {
             verify(mCsipSetCoordinatorLockCallback, times(1))
                     .onGroupLockSet(group,
-                            BluetoothCsipSetCoordinator.GROUP_LOCK_FAILED_LOCKED_BY_OTHER, true);
+                    BluetoothStatusCodes.ERROR_CSIP_GROUP_LOCKED_BY_OTHER, true);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 94d9698..d06f75e 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -756,15 +756,6 @@
     field protected java.util.List<android.bluetooth.BluetoothGattService> mIncludedServices;
   }
 
-  public final class BluetoothHapClient implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
-    method public void close();
-    method protected void finalize();
-    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
-    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_HAP_CONNECTION_STATE_CHANGED = "android.bluetooth.action.HAP_CONNECTION_STATE_CHANGED";
-  }
-
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
@@ -923,6 +914,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getGroupId(@NonNull android.bluetooth.BluetoothDevice);
     field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
+    field public static final int GROUP_ID_INVALID = -1; // 0xffffffff
   }
 
   public final class BluetoothLeAudioCodecConfig implements android.os.Parcelable {
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 5188e2a..f9df162 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -157,6 +157,32 @@
     field public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22; // 0x16
   }
 
+  public final class BluetoothHapClient implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
+    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.BluetoothHapPresetInfo getActivePresetInfo(@NonNull android.bluetooth.BluetoothDevice);
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothHapPresetInfo> getAllPresetInfo(@NonNull android.bluetooth.BluetoothDevice);
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothHapClient.Callback);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void selectPreset(@NonNull android.bluetooth.BluetoothDevice, int);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void selectPresetForGroup(int, int);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setPresetName(@NonNull android.bluetooth.BluetoothDevice, int, @NonNull String);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setPresetNameForGroup(int, int, @NonNull String);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void unregisterCallback(@NonNull android.bluetooth.BluetoothHapClient.Callback);
+    field @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static final String ACTION_HAP_CONNECTION_STATE_CHANGED = "android.bluetooth.action.HAP_CONNECTION_STATE_CHANGED";
+  }
+
+  public static interface BluetoothHapClient.Callback {
+    method public void onActivePresetChanged(@NonNull android.bluetooth.BluetoothDevice, int);
+    method public void onPresetInfoChanged(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.List<android.bluetooth.BluetoothHapPresetInfo>, int);
+    method public void onSelectActivePresetFailed(@NonNull android.bluetooth.BluetoothDevice, int);
+    method public void onSelectActivePresetForGroupFailed(int, int);
+    method public void onSetPresetNameFailed(@NonNull android.bluetooth.BluetoothDevice, int);
+    method public void onSetPresetNameForGroupFailed(int, int);
+  }
+
   public final class BluetoothHapPresetInfo implements android.os.Parcelable {
     method public int getIndex();
     method @NonNull public String getName();
@@ -219,6 +245,12 @@
 
   public final class BluetoothLeAudio implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getAudioLocation(@NonNull android.bluetooth.BluetoothDevice);
+    field @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static final String ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED = "android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED";
+    field @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static final String ACTION_LE_AUDIO_GROUP_NODE_STATUS_CHANGED = "android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED";
+    field public static final String EXTRA_LE_AUDIO_GROUP_ID = "android.bluetooth.extra.LE_AUDIO_GROUP_ID";
+    field public static final String EXTRA_LE_AUDIO_GROUP_NODE_STATUS = "android.bluetooth.extra.LE_AUDIO_GROUP_NODE_STATUS";
+    field public static final int GROUP_NODE_ADDED = 1; // 0x1
+    field public static final int GROUP_NODE_REMOVED = 2; // 0x2
   }
 
   public final class BluetoothLeAudioCodecConfigMetadata implements android.os.Parcelable {
@@ -477,6 +509,11 @@
     field public static final int ERROR_AUDIO_ROUTE_BLOCKED = 1118; // 0x45e
     field public static final int ERROR_BAD_PARAMETERS = 21; // 0x15
     field public static final int ERROR_CALL_ACTIVE = 1119; // 0x45f
+    field public static final int ERROR_CSIP_GROUP_LOCKED_BY_OTHER = 1208; // 0x4b8
+    field public static final int ERROR_CSIP_INVALID_GROUP_ID = 1207; // 0x4b7
+    field public static final int ERROR_CSIP_LOCKED_GROUP_MEMBER_LOST = 1209; // 0x4b9
+    field public static final int ERROR_HAP_INVALID_PRESET_INDEX = 1211; // 0x4bb
+    field public static final int ERROR_HAP_PRESET_NAME_TOO_LONG = 1210; // 0x4ba
     field public static final int ERROR_HARDWARE_GENERIC = 20; // 0x14
     field public static final int ERROR_LE_BROADCAST_ASSISTANT_DUPLICATE_ADDITION = 1203; // 0x4b3
     field public static final int ERROR_LE_BROADCAST_ASSISTANT_INVALID_SOURCE_ID = 1202; // 0x4b2
@@ -491,6 +528,7 @@
     field public static final int ERROR_PROFILE_NOT_CONNECTED = 14; // 0xe
     field public static final int ERROR_REMOTE_LINK_ERROR = 25; // 0x19
     field public static final int ERROR_REMOTE_NOT_ENOUGH_RESOURCES = 23; // 0x17
+    field public static final int ERROR_REMOTE_OPERATION_NOT_SUPPORTED = 24; // 0x18
     field public static final int ERROR_REMOTE_OPERATION_REJECTED = 24; // 0x18
     field public static final int ERROR_TIMEOUT = 15; // 0xf
     field public static final int NOT_ALLOWED = 401; // 0x191
diff --git a/framework/java/android/bluetooth/BluetoothCsipSetCoordinator.java b/framework/java/android/bluetooth/BluetoothCsipSetCoordinator.java
index ba57ec4..955920c 100644
--- a/framework/java/android/bluetooth/BluetoothCsipSetCoordinator.java
+++ b/framework/java/android/bluetooth/BluetoothCsipSetCoordinator.java
@@ -21,6 +21,7 @@
 
 import android.Manifest;
 import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -37,6 +38,8 @@
 
 import com.android.modules.utils.SynchronousResultReceiver;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -49,7 +52,7 @@
 /**
  * This class provides the public APIs to control the Bluetooth CSIP set coordinator.
  *
- * <p>BluetoothCsipSetCoordinator is a proxy object for controlling the Bluetooth VC
+ * <p>BluetoothCsipSetCoordinator is a proxy object for controlling the Bluetooth CSIP set
  * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
  * the BluetoothCsipSetCoordinator proxy object.
  *
@@ -66,10 +69,29 @@
      */
     @SystemApi
     public interface ClientLockCallback {
+        /** @hide */
+        @IntDef(value = {
+                BluetoothStatusCodes.SUCCESS,
+                BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED,
+                BluetoothStatusCodes.ERROR_CSIP_INVALID_GROUP_ID,
+                BluetoothStatusCodes.ERROR_CSIP_GROUP_LOCKED_BY_OTHER,
+                BluetoothStatusCodes.ERROR_CSIP_LOCKED_GROUP_MEMBER_LOST,
+                BluetoothStatusCodes.ERROR_UNKNOWN,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        @interface Status {}
+
         /**
+         * Callback is invoken as a result on {@link #groupLock()}.
+         *
+         * @param groupId group identifier
+         * @param opStatus status of lock operation
+         * @param isLocked inidcates if group is locked
+         *
          * @hide
          */
-        @SystemApi void onGroupLockSet(int groupId, int opStatus, boolean isLocked);
+        @SystemApi
+        void onGroupLockSet(int groupId, @Status int opStatus, boolean isLocked);
     }
 
     private static class BluetoothCsipSetCoordinatorLockCallbackDelegate
@@ -177,55 +199,6 @@
      */
     public static final int GROUP_ID_INVALID = IBluetoothCsipSetCoordinator.CSIS_GROUP_ID_INVALID;
 
-    /**
-     * Indicating that group was locked with success.
-     *
-     * @hide
-     */
-    public static final int GROUP_LOCK_SUCCESS = 0;
-
-    /**
-     * Indicating that group locked failed due to invalid group ID.
-     *
-     * @hide
-     */
-    public static final int GROUP_LOCK_FAILED_INVALID_GROUP = 1;
-
-    /**
-     * Indicating that group locked failed due to empty group.
-     *
-     * @hide
-     */
-    public static final int GROUP_LOCK_FAILED_GROUP_EMPTY = 2;
-
-    /**
-     * Indicating that group locked failed due to group members being disconnected.
-     *
-     * @hide
-     */
-    public static final int GROUP_LOCK_FAILED_GROUP_NOT_CONNECTED = 3;
-
-    /**
-     * Indicating that group locked failed due to group member being already locked.
-     *
-     * @hide
-     */
-    public static final int GROUP_LOCK_FAILED_LOCKED_BY_OTHER = 4;
-
-    /**
-     * Indicating that group locked failed due to other reason.
-     *
-     * @hide
-     */
-    public static final int GROUP_LOCK_FAILED_OTHER_REASON = 5;
-
-    /**
-     * Indicating that group member in locked state was lost.
-     *
-     * @hide
-     */
-    public static final int LOCKED_GROUP_MEMBER_LOST = 6;
-
     private final BluetoothAdapter mAdapter;
     private final AttributionSource mAttributionSource;
     private final BluetoothProfileConnector<IBluetoothCsipSetCoordinator> mProfileConnector =
diff --git a/framework/java/android/bluetooth/BluetoothHapClient.java b/framework/java/android/bluetooth/BluetoothHapClient.java
index 992e906..2b245bc 100644
--- a/framework/java/android/bluetooth/BluetoothHapClient.java
+++ b/framework/java/android/bluetooth/BluetoothHapClient.java
@@ -19,10 +19,13 @@
 
 import static android.bluetooth.BluetoothUtils.getSyncTimeout;
 
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
 import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
 import android.content.AttributionSource;
 import android.content.Context;
@@ -33,8 +36,11 @@
 
 import com.android.modules.utils.SynchronousResultReceiver;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Executor;
 import java.util.concurrent.TimeoutException;
 
 
@@ -44,7 +50,9 @@
  * <p>BluetoothHapClient is a proxy object for controlling the Bluetooth HAP
  * Service client via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the
  * BluetoothHapClient proxy object.
+ * @hide
  */
+@SystemApi
 public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable {
     private static final String TAG = "BluetoothHapClient";
     private static final boolean DBG = false;
@@ -53,6 +61,126 @@
     private CloseGuard mCloseGuard;
 
     /**
+     * This class provides callbacks mechanism for the BluetoothHapClient profile.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface Callback {
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(value = {
+                BluetoothStatusCodes.ERROR_UNKNOWN,
+                BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST,
+                BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST,
+                BluetoothStatusCodes.REASON_REMOTE_REQUEST,
+                BluetoothStatusCodes.REASON_SYSTEM_POLICY,
+                BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED,
+                BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED,
+                BluetoothStatusCodes.ERROR_HAP_PRESET_NAME_TOO_LONG,
+                BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX,
+                BluetoothStatusCodes.ERROR_CSIP_INVALID_GROUP_ID,
+        })
+        @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.
+         *
+         * @param device remote device,
+         * @param presetIndex the currently active preset index.
+         *
+         * @hide
+         */
+        @SystemApi
+        void onActivePresetChanged(@NonNull BluetoothDevice device, int presetIndex);
+
+        /**
+         * Invoked inform about the result of a failed preset change attempt.
+         *
+         * @param device remote device,
+         * @param statusCode failure reason.
+         *
+         * @hide
+         */
+        @SystemApi
+        void onSelectActivePresetFailed(@NonNull BluetoothDevice device, @Status int statusCode);
+
+        /**
+         * Invoked to inform about the result of a failed preset change attempt.
+         *
+         * The implementation will try to restore the state for every device back to original
+         *
+         * @param hapGroupId valid HAP group ID,
+         * @param statusCode failure reason.
+         *
+         * @hide
+         */
+        @SystemApi
+        void onSelectActivePresetForGroupFailed(int hapGroupId, @Status int statusCode);
+
+        /**
+         * Invoked to inform about the preset list changes.
+         *
+         * @param device remote device,
+         * @param presetInfoList a list of all preset information on the target device
+         * @param statusCode reason for the preset list change
+         *
+         * @hide
+         */
+        @SystemApi
+        void onPresetInfoChanged(@NonNull BluetoothDevice device,
+                @NonNull List<BluetoothHapPresetInfo> presetInfoList,
+                @Status int statusCode);
+
+        /**
+         * Invoked to inform about HA device's feature set.
+         *
+         * @param device remote device
+         * @param hapFeatures 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}.
+         *
+         * @hide
+         */
+        void onHapFeaturesAvailable(@NonNull BluetoothDevice device, int hapFeatures);
+
+        /**
+         * Invoked to inform about the failed preset rename attempt.
+         *
+         * @param device remote device
+         * @param status Failure reason code.
+         * @hide
+         */
+        @SystemApi
+        void onSetPresetNameFailed(@NonNull BluetoothDevice device, @Status int status);
+
+        /**
+         * Invoked to inform about the failed preset rename attempt.
+         *
+         * The implementation will try to restore the state for every device back to original
+         *
+         * @param hapGroupId valid HAP group ID,
+         * @param status Failure reason code.
+         * @hide
+         */
+        @SystemApi
+        void onSetPresetNameForGroupFailed(int hapGroupId, @Status int 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
      * the left and right side and each device will have their own connection state changes.
@@ -67,9 +195,14 @@
      * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
      * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
      * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+     * @hide
      */
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_HAP_CONNECTION_STATE_CHANGED =
             "android.bluetooth.action.HAP_CONNECTION_STATE_CHANGED";
@@ -84,9 +217,9 @@
      * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
      * <li> {@link #EXTRA_HAP_FEATURES} - Supported features map. </li>
      * </ul>
-     *
      * @hide
      */
+    @RequiresBluetoothConnectPermission
     @RequiresPermission(allOf = {
             android.Manifest.permission.BLUETOOTH_CONNECT,
             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -461,6 +594,63 @@
     }
 
     /**
+     * Register a {@link Callback} that will be invoked during the
+     * operation of this profile.
+     *
+     * Repeated registration of the same <var>callback</var> object will have no effect after
+     * the first call to this method, even when the <var>executor</var> is different. API caller
+     * would have to call {@link #unregisterCallback(Callback)} with
+     * the same callback object before registering it again.
+     *
+     * @param executor an {@link Executor} to execute given callback
+     * @param callback user implementation of the {@link Callback}
+     * @throws IllegalArgumentException if a null executor, sink, or callback is given
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public void registerCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull Callback callback) {
+        if (executor == null) {
+            throw new IllegalArgumentException("executor cannot be null");
+        }
+        if (callback == null) {
+            throw new IllegalArgumentException("callback cannot be null");
+        }
+        if (DBG) log("registerCallback");
+        throw new UnsupportedOperationException("Not Implemented");
+    }
+
+    /**
+     * Unregister the specified {@link Callback}.
+     * <p>The same {@link Callback} object used when calling
+     * {@link #registerCallback(Executor, Callback)} must be used.
+     *
+     * <p>Callbacks are automatically unregistered when application process goes away
+     *
+     * @param callback user implementation of the {@link Callback}
+     * @throws IllegalArgumentException when callback is null or when no callback is registered
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public void unregisterCallback(@NonNull Callback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback cannot be null");
+        }
+        if (DBG) log("unregisterCallback");
+        throw new UnsupportedOperationException("Not Implemented");
+    }
+
+    /**
      * Set connection policy of the profile
      *
      * <p> The device should already be paired.
@@ -472,6 +662,7 @@
      * @return true if connectionPolicy is set, false on error
      * @hide
      */
+    @SystemApi
     @RequiresBluetoothConnectPermission
     @RequiresPermission(allOf = {
             android.Manifest.permission.BLUETOOTH_CONNECT,
@@ -510,8 +701,12 @@
      * @return connection policy of the device
      * @hide
      */
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
     public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
         if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothHapClient service = getService();
@@ -533,10 +728,15 @@
 
     /**
      * {@inheritDoc}
+     * @hide
      */
-    @Override
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    @Override
     public @NonNull List<BluetoothDevice> getConnectedDevices() {
         if (VDBG) Log.d(TAG, "getConnectedDevices()");
         final IBluetoothHapClient service = getService();
@@ -558,10 +758,15 @@
 
     /**
      * {@inheritDoc}
+     * @hide
      */
-    @Override
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    @Override
     public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
             @NonNull int[] states) {
         if (VDBG) Log.d(TAG, "getDevicesMatchingConnectionStates()");
@@ -584,10 +789,15 @@
 
     /**
      * {@inheritDoc}
+     * @hide
      */
-    @Override
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    @Override
     public @BluetoothProfile.BtProfileState int getConnectionState(
             @NonNull BluetoothDevice device) {
         if (VDBG) Log.d(TAG, "getConnectionState(" + device + ")");
@@ -627,7 +837,10 @@
      * @hide
      */
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
     public int getHapGroup(@NonNull BluetoothDevice device) {
         final IBluetoothHapClient service = getService();
         final int defaultValue = HAP_GROUP_UNAVAILABLE;
@@ -647,44 +860,73 @@
     }
 
     /**
-     * Gets the currently active preset for a HA device
+     * Gets the currently active preset for a HA device.
      *
      * @param device is the device for which we want to set the active preset
      * @return active preset index
      * @hide
      */
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
-    public boolean getActivePresetIndex(@NonNull BluetoothDevice device) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public int getActivePresetIndex(@NonNull BluetoothDevice device) {
         final IBluetoothHapClient service = getService();
-        final boolean defaultValue = false;
+        final int defaultValue = PRESET_INDEX_UNAVAILABLE;
         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();
-                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()));
-            }
+            // 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()));
+            // }
         }
         return defaultValue;
     }
 
     /**
+     * Get the currently active preset info for a remote device.
+     *
+     * @param device is the device for which we want to get the preset name
+     * @return currently active preset info if selected, null if preset info is not available
+     *         for the remote device
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED
+    })
+    public @Nullable BluetoothHapPresetInfo getActivePresetInfo(@NonNull BluetoothDevice device) {
+        // TODO(b/216639668)
+        return null;
+    }
+
+    /**
      * Selects the currently active preset for a HA device
      *
+     * On success, {@link Callback#onActivePresetChanged(BluetoothDevice, int)} will be called with
+     * reason code {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}
+     * On failure, {@link Callback#onSelectActivePresetFailed(BluetoothDevice, int)} will be called.
+     *
      * @param device is the device for which we want to set the active preset
      * @param presetIndex is an index of one of the available presets
-     * @return true if valid request was sent, false otherwise
      * @hide
      */
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT,
-            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
-    public boolean selectActivePreset(@NonNull BluetoothDevice device, int presetIndex) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED
+    })
+    public void selectPreset(@NonNull BluetoothDevice device, int presetIndex) {
         final IBluetoothHapClient service = getService();
         final boolean defaultValue = false;
         if (service == null) {
@@ -692,31 +934,39 @@
             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);
-                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+                recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
             } catch (RemoteException | TimeoutException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
             }
         }
-        return defaultValue;
     }
 
     /**
-     * Selects the currently active preset for a HA device group.
+     * Selects the currently active preset for a Hearing Aid device group.
      *
      * <p> This group call may replace multiple device calls if those are part of the
      * valid HAS group. Note that binaural HA devices may or may not support group.
      *
+     * On success, {@link Callback#onActivePresetChanged(BluetoothDevice, int)} will be called
+     * for each device within the group with reason code
+     * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}
+     * On failure, {@link Callback#onSelectActivePresetFailed(BluetoothDevice, int)} will be called
+     * for each device within the group.
+     *
      * @param groupId is the device group identifier for which want to set the active preset
      * @param presetIndex is an index of one of the available presets
-     * @return true if valid group request was sent, false otherwise
      * @hide
      */
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT,
-            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
-    public boolean groupSelectActivePreset(int groupId, int presetIndex) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED
+    })
+    public void selectPresetForGroup(int groupId, int presetIndex) {
         final IBluetoothHapClient service = getService();
         final boolean defaultValue = false;
         if (service == null) {
@@ -724,14 +974,14 @@
             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);
-                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+                recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
             } catch (RemoteException | TimeoutException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
             }
         }
-        return defaultValue;
     }
 
     /**
@@ -741,13 +991,14 @@
      * does not necessarily mean a higher preset index.
      *
      * @param device is the device for which we want to set the active preset
-     * @return true if valid request was sent, false otherwise
      * @hide
      */
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT,
-            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
-    public boolean nextActivePreset(@NonNull BluetoothDevice device) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED
+    })
+    public void switchToNextPreset(@NonNull BluetoothDevice device) {
         final IBluetoothHapClient service = getService();
         final boolean defaultValue = false;
         if (service == null) {
@@ -755,14 +1006,14 @@
             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);
-                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+                recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
             } catch (RemoteException | TimeoutException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
             }
         }
-        return defaultValue;
     }
 
     /**
@@ -774,13 +1025,14 @@
      * valid HAS group. Note that binaural HA devices may or may not support group.
      *
      * @param groupId is the device group identifier for which want to set the active preset
-     * @return true if valid group request was sent, false otherwise
      * @hide
      */
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT,
-            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
-    public boolean groupNextActivePreset(int groupId) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED
+    })
+    public void switchToNextPresetForGroup(int groupId) {
         final IBluetoothHapClient service = getService();
         final boolean defaultValue = false;
         if (service == null) {
@@ -788,14 +1040,14 @@
             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);
-                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+                recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
             } catch (RemoteException | TimeoutException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
             }
         }
-        return defaultValue;
     }
 
     /**
@@ -805,13 +1057,14 @@
      * does not necessarily mean a lower preset index.
      *
      * @param device is the device for which we want to set the active preset
-     * @return true if valid request was sent, false otherwise
      * @hide
      */
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT,
-            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
-    public boolean previousActivePreset(@NonNull BluetoothDevice device) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED
+    })
+    public void switchToPreviousPreset(@NonNull BluetoothDevice device) {
         final IBluetoothHapClient service = getService();
         final boolean defaultValue = false;
         if (service == null) {
@@ -819,14 +1072,14 @@
             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);
-                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+                recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
             } catch (RemoteException | TimeoutException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
             }
         }
-        return defaultValue;
     }
 
     /**
@@ -838,13 +1091,14 @@
      * valid HAS group. Note that binaural HA devices may or may not support group.
      *
      * @param groupId is the device group identifier for which want to set the active preset
-     * @return true if valid group request was sent, false otherwise
      * @hide
      */
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT,
-            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
-    public boolean groupPreviousActivePreset(int groupId) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED
+    })
+    public void switchToPreviousPresetForGroup(int groupId) {
         final IBluetoothHapClient service = getService();
         final boolean defaultValue = false;
         if (service == null) {
@@ -852,14 +1106,14 @@
             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);
-                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+                recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
             } catch (RemoteException | TimeoutException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
             }
         }
-        return defaultValue;
     }
 
     /**
@@ -867,54 +1121,62 @@
      *
      * @param device is the device for which we want to get the preset name
      * @param presetIndex is an index of one of the available presets
-     * @return true if valid request was sent, false otherwise
+     * @return preset info
      * @hide
      */
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT,
-            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
-    public boolean getPresetInfo(@NonNull BluetoothDevice device, int presetIndex) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED
+    })
+    public @NonNull BluetoothHapPresetInfo getPresetInfo(@NonNull BluetoothDevice device,
+            int presetIndex) {
         final IBluetoothHapClient service = getService();
-        final boolean defaultValue = false;
+        final BluetoothHapPresetInfo.Builder builder = new BluetoothHapPresetInfo.Builder();
         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();
-                service.getPresetInfo(device, presetIndex, mAttributionSource, recv);
-                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
-            } catch (RemoteException | TimeoutException e) {
-                Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
-            }
+            // 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()));
+            // }
         }
-        return defaultValue;
+        return builder.build();
     }
 
     /**
-     * Requests all presets info
+     * Get all preset info for a particular device
      *
      * @param device is the device for which we want to get all presets info
-     * @return true if request was processed, false otherwise
+     * @return a list of all known preset info
      * @hide
      */
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT,
-            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
-    public boolean getAllPresetsInfo(@NonNull BluetoothDevice device) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED
+    })
+    public @NonNull List<BluetoothHapPresetInfo> getAllPresetInfo(@NonNull BluetoothDevice device) {
         final IBluetoothHapClient service = getService();
-        final boolean defaultValue = false;
+        final List<BluetoothHapPresetInfo> defaultValue = new ArrayList<BluetoothHapPresetInfo>();
         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();
-                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()));
-            }
+            // 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()));
+            // }
         }
         return defaultValue;
     }
@@ -927,8 +1189,10 @@
      * @hide
      */
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT,
-            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED
+    })
     public boolean getFeatures(@NonNull BluetoothDevice device) {
         final IBluetoothHapClient service = getService();
         final boolean defaultValue = false;
@@ -948,21 +1212,28 @@
     }
 
     /**
-     * Sets the preset name
+     * Sets the preset name for a particular device
      *
-     * <p> Note that the name length is restricted to 30 characters.
+     * <p> Note that the name length is restricted to 40 characters.
+     *
+     * On success, {@link Callback#onPresetInfoChanged(BluetoothDevice, List, int)}
+     * with a new name will be called and reason code
+     * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}
+     * On failure, {@link Callback#onSetPresetNameFailed(BluetoothDevice, int)} will be called.
      *
      * @param device is the device for which we want to get the preset name
      * @param presetIndex is an index of one of the available presets
-     * @param name is a new name for a preset
-     * @return true if valid request was sent, false otherwise
+     * @param name is a new name for a preset, maximum length is 40 characters
      * @hide
      */
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT,
-            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
-    public boolean setPresetName(@NonNull BluetoothDevice device, int presetIndex,
-                                 @NonNull String name) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED
+    })
+    public void setPresetName(@NonNull BluetoothDevice device, int presetIndex,
+            @NonNull String name) {
         final IBluetoothHapClient service = getService();
         final boolean defaultValue = false;
         if (service == null) {
@@ -970,31 +1241,38 @@
             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);
-                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+                recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
             } catch (RemoteException | TimeoutException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
             }
         }
-        return defaultValue;
     }
 
     /**
-     * Sets the preset name
+     * Sets the name for a hearing aid preset.
      *
-     * <p> Note that the name length is restricted to 30 characters.
+     * <p> Note that the name length is restricted to 40 characters.
+     *
+     * On success, {@link Callback#onPresetInfoChanged(BluetoothDevice, List, int)}
+     * with a new name will be called for each device within the group with reason code
+     * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}
+     * On failure, {@link Callback#onSetPresetNameForGroupFailed(int, int)} will be invoked
      *
      * @param groupId is the device group identifier
      * @param presetIndex is an index of one of the available presets
-     * @param name is a new name for a preset
-     * @return true if valid request was sent, false otherwise
+     * @param name is a new name for a preset, maximum length is 40 characters
      * @hide
      */
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT,
-            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
-    public boolean groupSetPresetName(int groupId, int presetIndex, @NonNull String name) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED
+    })
+    public void setPresetNameForGroup(int groupId, int presetIndex, @NonNull String name) {
         final IBluetoothHapClient service = getService();
         final boolean defaultValue = false;
         if (service == null) {
@@ -1002,14 +1280,14 @@
             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);
-                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+                recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
             } catch (RemoteException | TimeoutException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
             }
         }
-        return defaultValue;
     }
 
     private boolean isEnabled() {
diff --git a/framework/java/android/bluetooth/BluetoothLeAudio.java b/framework/java/android/bluetooth/BluetoothLeAudio.java
index cb543bd..aa34d0d 100644
--- a/framework/java/android/bluetooth/BluetoothLeAudio.java
+++ b/framework/java/android/bluetooth/BluetoothLeAudio.java
@@ -92,9 +92,13 @@
      *
      * @hide
      */
+    @SystemApi
     @RequiresLegacyBluetoothPermission
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED =
             "android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED";
@@ -112,12 +116,15 @@
      *
      * @hide
      */
-    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    @SystemApi
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_LE_AUDIO_GROUP_NODE_STATUS_CHANGED =
             "android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED";
 
-
     /**
      * Intent used to broadcast group status information.
      *
@@ -256,8 +263,6 @@
 
     /**
      * This represents an invalid group ID.
-     *
-     * @hide
      */
     public static final int GROUP_ID_INVALID = IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
 
@@ -272,6 +277,7 @@
      * Contains group id.
      * @hide
      */
+    @SystemApi
     public static final String EXTRA_LE_AUDIO_GROUP_ID =
             "android.bluetooth.extra.LE_AUDIO_GROUP_ID";
 
@@ -285,6 +291,7 @@
      * <p>
      * @hide
      */
+    @SystemApi
     public static final String EXTRA_LE_AUDIO_GROUP_NODE_STATUS =
             "android.bluetooth.extra.LE_AUDIO_GROUP_NODE_STATUS";
 
@@ -348,12 +355,14 @@
      * Indicating that node has been added to the group.
      * @hide
      */
+    @SystemApi
     public static final int GROUP_NODE_ADDED = IBluetoothLeAudio.GROUP_NODE_ADDED;
 
     /**
      * Indicating that node has been removed from the group.
      * @hide
      */
+    @SystemApi
     public static final int GROUP_NODE_REMOVED = IBluetoothLeAudio.GROUP_NODE_REMOVED;
 
     private final BluetoothProfileConnector<IBluetoothLeAudio> mProfileConnector =
@@ -675,7 +684,8 @@
      * Get device group id. Devices with same group id belong to same group (i.e left and right
      * earbud)
      * @param device LE Audio capable device
-     * @return group id that this device currently belongs to
+     * @return group id that this device currently belongs to, {@link #GROUP_ID_INVALID} when this
+     *         device does not belong to any group
      */
     @RequiresLegacyBluetoothPermission
     @RequiresBluetoothConnectPermission
diff --git a/framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java b/framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java
index 81f5d18..870ab0f 100644
--- a/framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java
+++ b/framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java
@@ -344,8 +344,7 @@
             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
     })
     @Override
-    @NonNull
-    public List<BluetoothDevice> getConnectedDevices() {
+    public @NonNull List<BluetoothDevice> getConnectedDevices() {
         return Collections.emptyList();
     }
 
diff --git a/framework/java/android/bluetooth/BluetoothStatusCodes.java b/framework/java/android/bluetooth/BluetoothStatusCodes.java
index 01e30db..8825c3e 100644
--- a/framework/java/android/bluetooth/BluetoothStatusCodes.java
+++ b/framework/java/android/bluetooth/BluetoothStatusCodes.java
@@ -221,6 +221,15 @@
     public static final int ERROR_ALREADY_IN_TARGET_STATE = 26;
 
     /**
+     * Indicates that the requested operation is not supported by the remote device
+     *
+     * Caller should stop trying this operation
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_REMOTE_OPERATION_NOT_SUPPORTED = 24;
+
+    /**
      * A GATT writeCharacteristic request is not permitted on the remote device.
      */
     public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200;
@@ -454,6 +463,48 @@
     public static final int ERROR_LE_CONTENT_METADATA_INVALID_OTHER = 1206;
 
     /**
+     * Indicates that provided group ID is invalid for the coordinated set
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_CSIP_INVALID_GROUP_ID = 1207;
+
+    /**
+     * Indicating that CSIP group locked failed due to group member being already locked.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_CSIP_GROUP_LOCKED_BY_OTHER = 1208;
+
+    /**
+     * Indicating that CSIP device has been lost while being locked.
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_CSIP_LOCKED_GROUP_MEMBER_LOST = 1209;
+
+    /**
+     * Indicates that the set preset name is too long.
+     * <p>
+     * Example solution: Try using shorter name.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_HAP_PRESET_NAME_TOO_LONG = 1210;
+
+    /**
+     * Indicates that provided preset index parameters is invalid
+     * <p>
+     * Example solution: Use preset index of a known existing preset.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_HAP_INVALID_PRESET_INDEX = 1211;
+
+    /**
      * Indicates that the RFCOMM listener could not be started due to the requested UUID already
      * being in use.
      *
diff --git a/system/binder/android/bluetooth/IBluetoothCsipSetCoordinator.aidl b/system/binder/android/bluetooth/IBluetoothCsipSetCoordinator.aidl
index e001edc..91b40e7 100644
--- a/system/binder/android/bluetooth/IBluetoothCsipSetCoordinator.aidl
+++ b/system/binder/android/bluetooth/IBluetoothCsipSetCoordinator.aidl
@@ -83,4 +83,12 @@
 
   const int CSIS_GROUP_ID_INVALID = -1;
   const int CSIS_GROUP_SIZE_UNKNOWN = 1;
+
+  const int CSIS_GROUP_LOCK_SUCCESS = 0;
+  const int CSIS_GROUP_LOCK_FAILED_INVALID_GROUP = 1;
+  const int CSIS_GROUP_LOCK_FAILED_GROUP_EMPTY = 2;
+  const int CSIS_GROUP_LOCK_FAILED_GROUP_NOT_CONNECTED = 3;
+  const int CSIS_GROUP_LOCK_FAILED_LOCKED_BY_OTHER = 4;
+  const int CSIS_GROUP_LOCK_FAILED_OTHER_REASON = 5;
+  const int CSIS_LOCKED_GROUP_MEMBER_LOST = 6;
 }