Introduce LE audio broadcast system APIs

* Rename BluetoothLeBroadcastSourceInfo to
  BluetoothLeBroadcastReceiveState so that it matches the name in the
  Bluetooth specification
* Added callbacks to BluetoothLeBroadcast so that caller that wait
  for asynchronouze operations with reason code in the hope to reduce
  potential race conditions
* Allow multiple broadcast to be set up on the same deivce if the device
  supports it
* Added ScanFilter to searchForSources() method and removed
  selectSources() method for BluetoothLeBroadcastAssistant so that the
  Bluetooth stack can automatically handle periodic sync after a
  Broadcast source is found and only do this for a limited number of
  devices
* Added structural APIs to store Broadcast Source and Group information
* Added unknown address type in BluetoothDevice

Bug: 208222281
Test: make
Tag: #feature
Ignore-AOSP-First: Merge conflict in master
Change-Id: If4c3af658b5bc1283d76e5d1899485a487ab7626
diff --git a/framework/api/current.txt b/framework/api/current.txt
index c7f671a..1e18dc7 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -527,6 +527,7 @@
     field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_UUID = "android.bluetooth.device.action.UUID";
     field public static final int ADDRESS_TYPE_PUBLIC = 0; // 0x0
     field public static final int ADDRESS_TYPE_RANDOM = 1; // 0x1
+    field public static final int ADDRESS_TYPE_UNKNOWN = 65535; // 0xffff
     field public static final int BOND_BONDED = 12; // 0xc
     field public static final int BOND_BONDING = 11; // 0xb
     field public static final int BOND_NONE = 10; // 0xa
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 69d4c8d..b4dd386 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -203,6 +203,183 @@
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getAudioLocation(@NonNull android.bluetooth.BluetoothDevice);
   }
 
+  public final class BluetoothLeAudioCodecConfigMetadata implements android.os.Parcelable {
+    method @NonNull public static android.bluetooth.BluetoothLeAudioCodecConfigMetadata fromRawBytes(@NonNull byte[]);
+    method public long getAudioLocation();
+    method @NonNull public byte[] getRawMetadata();
+    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothLeAudioCodecConfigMetadata> CREATOR;
+  }
+
+  public static final class BluetoothLeAudioCodecConfigMetadata.Builder {
+    ctor public BluetoothLeAudioCodecConfigMetadata.Builder();
+    ctor public BluetoothLeAudioCodecConfigMetadata.Builder(@NonNull android.bluetooth.BluetoothLeAudioCodecConfigMetadata);
+    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfigMetadata build();
+    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfigMetadata.Builder setAudioLocation(long);
+  }
+
+  public final class BluetoothLeAudioContentMetadata implements android.os.Parcelable {
+    method @NonNull public static android.bluetooth.BluetoothLeAudioContentMetadata fromRawBytes(@NonNull byte[]);
+    method @Nullable public String getLanguage();
+    method @Nullable public String getProgramInfo();
+    method @NonNull public byte[] getRawMetadata();
+    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothLeAudioContentMetadata> CREATOR;
+  }
+
+  public static final class BluetoothLeAudioContentMetadata.Builder {
+    ctor public BluetoothLeAudioContentMetadata.Builder();
+    ctor public BluetoothLeAudioContentMetadata.Builder(@NonNull android.bluetooth.BluetoothLeAudioContentMetadata);
+    method @NonNull public android.bluetooth.BluetoothLeAudioContentMetadata build();
+    method @NonNull public android.bluetooth.BluetoothLeAudioContentMetadata.Builder setLanguage(@Nullable String);
+    method @NonNull public android.bluetooth.BluetoothLeAudioContentMetadata.Builder setProgramInfo(@Nullable String);
+  }
+
+  public final class BluetoothLeBroadcast implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothLeBroadcastMetadata> getAllBroadcastMetadata();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getMaximumNumberOfBroadcast();
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean isPlaying(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.BluetoothLeBroadcast.Callback);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void startBroadcast(@NonNull android.bluetooth.BluetoothLeAudioContentMetadata, @Nullable byte[]);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void stopBroadcast(int);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void unregisterCallback(@NonNull android.bluetooth.BluetoothLeBroadcast.Callback);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void updateBroadcast(int, @NonNull android.bluetooth.BluetoothLeAudioContentMetadata);
+  }
+
+  public static interface BluetoothLeBroadcast.Callback {
+    method public void onBroadcastMetadataChanged(int, @NonNull android.bluetooth.BluetoothLeBroadcastMetadata);
+    method public void onBroadcastStartFailed(int);
+    method public void onBroadcastStarted(int, int);
+    method public void onBroadcastStopFailed(int);
+    method public void onBroadcastStopped(int, int);
+    method public void onBroadcastUpdateFailed(int, int);
+    method public void onBroadcastUpdated(int, int);
+    method public void onPlaybackStarted(int, int);
+    method public void onPlaybackStopped(int, int);
+  }
+
+  public final class BluetoothLeBroadcastAssistant implements android.bluetooth.BluetoothProfile {
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void addSource(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothLeBroadcastMetadata, boolean);
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothLeBroadcastReceiveState> getAllSources(@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(@NonNull 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 public int getMaximumSourceCapacity(@NonNull android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean isSearchInProgress();
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void modifySource(@NonNull android.bluetooth.BluetoothDevice, int, @NonNull android.bluetooth.BluetoothLeBroadcastMetadata);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothLeBroadcastAssistant.Callback);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void removeSource(@NonNull android.bluetooth.BluetoothDevice, 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_SCAN, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void startSearchingForSources(@NonNull java.util.List<android.bluetooth.le.ScanFilter>);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void stopSearchingForSources();
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void unregisterCallback(@NonNull android.bluetooth.BluetoothLeBroadcastAssistant.Callback);
+    field @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.action.CONNECTION_STATE_CHANGED";
+  }
+
+  public static interface BluetoothLeBroadcastAssistant.Callback {
+    method public void onReceiveStateChanged(@NonNull android.bluetooth.BluetoothDevice, int, @NonNull android.bluetooth.BluetoothLeBroadcastReceiveState);
+    method public void onSearchStartFailed(int);
+    method public void onSearchStarted(int);
+    method public void onSearchStopFailed(int);
+    method public void onSearchStopped(int);
+    method public void onSourceAddFailed(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothLeBroadcastMetadata, int);
+    method public void onSourceAdded(@NonNull android.bluetooth.BluetoothDevice, int, int);
+    method public void onSourceFound(@NonNull android.bluetooth.BluetoothLeBroadcastMetadata);
+    method public void onSourceModified(@NonNull android.bluetooth.BluetoothDevice, int, int);
+    method public void onSourceModifyFailed(@NonNull android.bluetooth.BluetoothDevice, int, int);
+    method public void onSourceRemoveFailed(@NonNull android.bluetooth.BluetoothDevice, int, int);
+    method public void onSourceRemoved(@NonNull android.bluetooth.BluetoothDevice, int, int);
+  }
+
+  public final class BluetoothLeBroadcastChannel implements android.os.Parcelable {
+    method public int getChannelIndex();
+    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfigMetadata getCodecMetadata();
+    method public boolean isSelected();
+    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothLeBroadcastChannel> CREATOR;
+  }
+
+  public static final class BluetoothLeBroadcastChannel.Builder {
+    ctor public BluetoothLeBroadcastChannel.Builder();
+    ctor public BluetoothLeBroadcastChannel.Builder(@NonNull android.bluetooth.BluetoothLeBroadcastChannel);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastChannel build();
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastChannel.Builder setChannelIndex(int);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastChannel.Builder setCodecMetadata(@NonNull android.bluetooth.BluetoothLeAudioCodecConfigMetadata);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastChannel.Builder setSelected(boolean);
+  }
+
+  public final class BluetoothLeBroadcastMetadata implements android.os.Parcelable {
+    method @Nullable public byte[] getBroadcastCode();
+    method public int getBroadcastId();
+    method public int getPaSyncInterval();
+    method @IntRange(from=0, to=16777215) public int getPresentationDelayMicros();
+    method public int getSourceAddressType();
+    method public int getSourceAdvertisingSid();
+    method @Nullable public android.bluetooth.BluetoothDevice getSourceDevice();
+    method @NonNull public java.util.List<android.bluetooth.BluetoothLeBroadcastSubgroup> getSubgroups();
+    method public boolean isEncrypted();
+    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothLeBroadcastMetadata> CREATOR;
+    field public static final int PA_SYNC_INTERVAL_UNKNOWN = 65535; // 0xffff
+  }
+
+  public static final class BluetoothLeBroadcastMetadata.Builder {
+    ctor public BluetoothLeBroadcastMetadata.Builder();
+    ctor public BluetoothLeBroadcastMetadata.Builder(@NonNull android.bluetooth.BluetoothLeBroadcastMetadata);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastMetadata.Builder addSubgroup(@NonNull android.bluetooth.BluetoothLeBroadcastSubgroup);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastMetadata build();
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastMetadata.Builder clearSubgroup();
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastMetadata.Builder setBroadcastCode(@Nullable byte[]);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastMetadata.Builder setBroadcastId(int);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastMetadata.Builder setEncrypted(boolean);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastMetadata.Builder setPaSyncInterval(int);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastMetadata.Builder setPresentationDelayMicros(@IntRange(from=0, to=16777215) int);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastMetadata.Builder setSourceAdvertisingSid(int);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastMetadata.Builder setSourceDevice(@Nullable android.bluetooth.BluetoothDevice, int);
+  }
+
+  public final class BluetoothLeBroadcastReceiveState implements android.os.Parcelable {
+    method @Nullable public byte[] getBadCode();
+    method public int getBigEncryptionState();
+    method @NonNull public java.util.List<java.lang.Long> getBisSyncState();
+    method public int getBroadcastId();
+    method public int getNumSubgroups();
+    method public int getPaSyncState();
+    method public int getSourceAddressType();
+    method public int getSourceAdvertisingSid();
+    method @NonNull public android.bluetooth.BluetoothDevice getSourceDevice();
+    method @IntRange(from=0, to=255) public int getSourceId();
+    method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioContentMetadata> getSubgroupMetadata();
+    field public static final int BIG_ENCRYPTION_STATE_BAD_CODE = 3; // 0x3
+    field public static final int BIG_ENCRYPTION_STATE_CODE_REQUIRED = 1; // 0x1
+    field public static final int BIG_ENCRYPTION_STATE_DECRYPTING = 2; // 0x2
+    field public static final int BIG_ENCRYPTION_STATE_NOT_ENCRYPTED = 0; // 0x0
+    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothLeBroadcastReceiveState> CREATOR;
+    field public static final int PA_SYNC_STATE_FAILED_TO_SYNCHRONIZE = 3; // 0x3
+    field public static final int PA_SYNC_STATE_IDLE = 0; // 0x0
+    field public static final int PA_SYNC_STATE_NO_PAST = 4; // 0x4
+    field public static final int PA_SYNC_STATE_SYNCHRONIZED = 2; // 0x2
+    field public static final int PA_SYNC_STATE_SYNCINFO_REQUEST = 1; // 0x1
+  }
+
+  public final class BluetoothLeBroadcastSubgroup implements android.os.Parcelable {
+    method @NonNull public java.util.List<android.bluetooth.BluetoothLeBroadcastChannel> getChannels();
+    method public long getCodecId();
+    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfigMetadata getCodecSpecificConfig();
+    method @NonNull public android.bluetooth.BluetoothLeAudioContentMetadata getContentMetadata();
+    method public boolean isNoChannelPreference();
+    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothLeBroadcastSubgroup> CREATOR;
+  }
+
+  public static final class BluetoothLeBroadcastSubgroup.Builder {
+    ctor public BluetoothLeBroadcastSubgroup.Builder();
+    ctor public BluetoothLeBroadcastSubgroup.Builder(@NonNull android.bluetooth.BluetoothLeBroadcastSubgroup);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastSubgroup.Builder addChannel(@NonNull android.bluetooth.BluetoothLeBroadcastChannel);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastSubgroup build();
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastSubgroup.Builder clearChannel();
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastSubgroup.Builder setCodecId(long);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastSubgroup.Builder setCodecSpecificConfig(@NonNull android.bluetooth.BluetoothLeAudioCodecConfigMetadata);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastSubgroup.Builder setContentMetadata(@NonNull android.bluetooth.BluetoothLeAudioContentMetadata);
+    method @NonNull public android.bluetooth.BluetoothLeBroadcastSubgroup.Builder setNoChannelPreference(boolean);
+  }
+
   public final class BluetoothMap implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
     method public void close();
     method protected void finalize();
@@ -263,6 +440,8 @@
     field public static final int CONNECTION_POLICY_FORBIDDEN = 0; // 0x0
     field public static final int CONNECTION_POLICY_UNKNOWN = -1; // 0xffffffff
     field public static final int HEADSET_CLIENT = 16; // 0x10
+    field public static final int LE_AUDIO_BROADCAST = 26; // 0x1a
+    field public static final int LE_AUDIO_BROADCAST_ASSISTANT = 29; // 0x1d
     field public static final int MAP_CLIENT = 18; // 0x12
     field public static final int PAN = 5; // 0x5
     field public static final int PBAP_CLIENT = 17; // 0x11
@@ -273,16 +452,34 @@
 
   public final class BluetoothStatusCodes {
     field public static final int ALLOWED = 400; // 0x190
+    field public static final int ERROR_ALREADY_IN_TARGET_STATE = 26; // 0x1a
     field public static final int ERROR_ANOTHER_ACTIVE_OOB_REQUEST = 1000; // 0x3e8
     field public static final int ERROR_AUDIO_DEVICE_ALREADY_CONNECTED = 1116; // 0x45c
     field public static final int ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED = 1117; // 0x45d
     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_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
+    field public static final int ERROR_LE_BROADCAST_INVALID_BROADCAST_ID = 1200; // 0x4b0
+    field public static final int ERROR_LE_BROADCAST_INVALID_CODE = 1201; // 0x4b1
+    field public static final int ERROR_LE_CONTENT_METADATA_INVALID_LANGUAGE = 1205; // 0x4b5
+    field public static final int ERROR_LE_CONTENT_METADATA_INVALID_OTHER = 1206; // 0x4b6
+    field public static final int ERROR_LE_CONTENT_METADATA_INVALID_PROGRAM_INFO = 1204; // 0x4b4
+    field public static final int ERROR_LOCAL_NOT_ENOUGH_RESOURCES = 22; // 0x16
     field public static final int ERROR_NOT_ACTIVE_DEVICE = 12; // 0xc
     field public static final int ERROR_NO_ACTIVE_DEVICES = 13; // 0xd
     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_REJECTED = 24; // 0x18
     field public static final int ERROR_TIMEOUT = 15; // 0xf
     field public static final int NOT_ALLOWED = 401; // 0x191
+    field public static final int REASON_LOCAL_APP_REQUEST = 16; // 0x10
+    field public static final int REASON_LOCAL_STACK_REQUEST = 17; // 0x11
+    field public static final int REASON_REMOTE_REQUEST = 18; // 0x12
+    field public static final int REASON_SYSTEM_POLICY = 19; // 0x13
     field public static final int RFCOMM_LISTENER_FAILED_TO_CLOSE_SERVER_SOCKET = 2004; // 0x7d4
     field public static final int RFCOMM_LISTENER_FAILED_TO_CREATE_SERVER_SOCKET = 2003; // 0x7d3
     field public static final int RFCOMM_LISTENER_NO_SOCKET_AVAILABLE = 2005; // 0x7d5
diff --git a/framework/java/android/bluetooth/BluetoothDevice.java b/framework/java/android/bluetooth/BluetoothDevice.java
index c43a519..4c254aa 100644
--- a/framework/java/android/bluetooth/BluetoothDevice.java
+++ b/framework/java/android/bluetooth/BluetoothDevice.java
@@ -1132,6 +1132,8 @@
             ADDRESS_TYPE_PUBLIC,
             /** Address is either resolvable, non-resolvable or static.*/
             ADDRESS_TYPE_RANDOM,
+            /** Address type is unknown or unavailable **/
+            ADDRESS_TYPE_UNKNOWN,
         }
     )
     public @interface AddressType {}
@@ -1140,6 +1142,8 @@
     public static final int ADDRESS_TYPE_PUBLIC = 0;
     /** Address is either resolvable, non-resolvable or static. */
     public static final int ADDRESS_TYPE_RANDOM = 1;
+    /** Address type is unknown or unavailable **/
+    public static final int ADDRESS_TYPE_UNKNOWN = 0xFFFF;
 
     private static final String NULL_MAC_ADDRESS = "00:00:00:00:00:00";
 
diff --git a/framework/java/android/bluetooth/BluetoothLeAudioCodecConfigMetadata.java b/framework/java/android/bluetooth/BluetoothLeAudioCodecConfigMetadata.java
new file mode 100644
index 0000000..4ca657c
--- /dev/null
+++ b/framework/java/android/bluetooth/BluetoothLeAudioCodecConfigMetadata.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class representing the codec specific config metadata information defined in the Basic Audio
+ * Profile.
+ *
+ * @hide
+ */
+@SystemApi
+public final class BluetoothLeAudioCodecConfigMetadata implements Parcelable {
+    private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
+
+    private final long mAudioLocation;
+    private final byte[] mRawMetadata;
+
+    private BluetoothLeAudioCodecConfigMetadata(long audioLocation, byte[] rawMetadata) {
+        mAudioLocation = audioLocation;
+        mRawMetadata = rawMetadata;
+    }
+
+    /**
+     * Get the audio location information as defined in the Generic Audio section of Bluetooth
+     * Assigned numbers.
+     *
+     * @return configured audio location, -1 if this metadata does not exist
+     * @hide
+     */
+    @SystemApi
+    public long getAudioLocation() {
+        return mAudioLocation;
+    }
+
+    /**
+     * Get the raw bytes of stream metadata in Bluetooth LTV format.
+     *
+     * Bluetooth LTV format for stream metadata is defined in the Generic Audio
+     * section of <a href="https://www.bluetooth.com/specifications/assigned-numbers/">Bluetooth Assigned Numbers</a>,
+     * including metadata that was not covered by the getter methods in this class.
+     *
+     * @return raw bytes of stream metadata in Bluetooth LTV format
+     * @hide
+     */
+    @SystemApi
+    public @NonNull byte[] getRawMetadata() {
+        return mRawMetadata;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(mAudioLocation);
+        if (mRawMetadata != null) {
+            out.writeInt(mRawMetadata.length);
+            out.writeByteArray(mRawMetadata);
+        } else {
+            out.writeInt(-1);
+        }
+    }
+
+    /**
+     * A {@link Parcelable.Creator} to create {@link BluetoothLeAudioCodecConfigMetadata} from
+     * parcel.
+     * @hide
+     */
+    @SystemApi
+    public static final @NonNull Parcelable.Creator<BluetoothLeAudioCodecConfigMetadata> CREATOR =
+            new Parcelable.Creator<BluetoothLeAudioCodecConfigMetadata>() {
+                @NonNull
+                public BluetoothLeAudioCodecConfigMetadata createFromParcel(@NonNull Parcel in) {
+                    long audioLocation = in.readLong();
+                    int rawMetadataLen = in.readInt();
+                    byte[] rawMetadata;
+                    if (rawMetadataLen != -1) {
+                        rawMetadata = new byte[rawMetadataLen];
+                        in.readByteArray(rawMetadata);
+                    } else {
+                        rawMetadata = new byte[0];
+                    }
+                    return new BluetoothLeAudioCodecConfigMetadata(audioLocation, rawMetadata);
+                }
+
+                public @NonNull BluetoothLeAudioCodecConfigMetadata[] newArray(int size) {
+                    return new BluetoothLeAudioCodecConfigMetadata[size];
+                }
+            };
+
+    /**
+     * Construct a {@link BluetoothLeAudioCodecConfigMetadata} from raw bytes.
+     *
+     * The byte array will be parsed and values for each getter will be populated
+     *
+     * Raw metadata cannot be set using builder in order to maintain raw bytes and getter value
+     * consistency
+     *
+     * @param rawBytes raw bytes of stream metadata in Bluetooth LTV format
+     * @return parsed {@link BluetoothLeAudioCodecConfigMetadata} object
+     * @throws IllegalArgumentException if <var>rawBytes</var> is null or when the raw bytes cannot
+     * be parsed to build the object
+     * @hide
+     */
+    @SystemApi
+    public static @NonNull BluetoothLeAudioCodecConfigMetadata fromRawBytes(
+            @NonNull byte[] rawBytes) {
+        if (rawBytes == null) {
+            throw new IllegalArgumentException("Raw bytes cannot be null");
+        }
+        return null;
+    }
+
+    /**
+     * Builder for {@link BluetoothLeAudioCodecConfigMetadata}.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+        private long mAudioLocation = UNKNOWN_VALUE_PLACEHOLDER;
+        private byte[] mRawMetadata = null;
+
+        /**
+         * Create an empty builder.
+         * @hide
+         */
+        @SystemApi
+        public Builder() {}
+
+        /**
+         * Create a builder with copies of information from original object.
+         *
+         * @param original original object
+         * @hide
+         */
+        @SystemApi
+        public Builder(@NonNull BluetoothLeAudioCodecConfigMetadata original) {
+            mAudioLocation = original.getAudioLocation();
+            mRawMetadata = original.getRawMetadata();
+        }
+
+        /**
+         * Set the audio location information as defined in the Generic Audio section of Bluetooth
+         * Assigned numbers.
+         *
+         * @param audioLocation configured audio location, -1 if does not exist
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setAudioLocation(long audioLocation) {
+            mAudioLocation = audioLocation;
+            return this;
+        }
+
+        /**
+         * Build {@link BluetoothLeAudioCodecConfigMetadata}.
+         *
+         * @return constructed {@link BluetoothLeAudioCodecConfigMetadata}
+         * @throws IllegalArgumentException if the object cannot be built
+         * @hide
+         */
+        @SystemApi
+        public @NonNull BluetoothLeAudioCodecConfigMetadata build() {
+            if (mRawMetadata == null) {
+                mRawMetadata = new byte[0];
+            }
+            return new BluetoothLeAudioCodecConfigMetadata(mAudioLocation, mRawMetadata);
+        }
+    }
+}
diff --git a/framework/java/android/bluetooth/BluetoothLeAudioContentMetadata.java b/framework/java/android/bluetooth/BluetoothLeAudioContentMetadata.java
new file mode 100644
index 0000000..47ab698
--- /dev/null
+++ b/framework/java/android/bluetooth/BluetoothLeAudioContentMetadata.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class representing the media metadata information defined in the Basic Audio Profile.
+ *
+ * @hide
+ */
+@SystemApi
+public final class BluetoothLeAudioContentMetadata implements Parcelable {
+    private final String mProgramInfo;
+    private final String mLanguage;
+    private final byte[] mRawMetadata;
+
+    private BluetoothLeAudioContentMetadata(String programInfo, String language,
+            byte[] rawMetadata) {
+        mProgramInfo = programInfo;
+        mLanguage = language;
+        mRawMetadata = rawMetadata;
+    }
+
+    /**
+     * Get the title and/or summary of Audio Stream content in UTF-8 format.
+     *
+     * @return title and/or summary of Audio Stream content in UTF-8 format, null if this metadata
+     * does not exist
+     * @hide
+     */
+    @SystemApi
+    public @Nullable String getProgramInfo() {
+        return mProgramInfo;
+    }
+
+    /**
+     * Get language of the audio stream in 3-byte, lower case language code as defined in ISO 639-3.
+     *
+     * @return ISO 639-3 formatted language code, null if this metadata does not exist
+     * @hide
+     */
+    @SystemApi
+    public @Nullable String getLanguage() {
+        return mLanguage;
+    }
+
+    /**
+     * Get the raw bytes of stream metadata in Bluetooth LTV format as defined in the Generic Audio
+     * section of <a href="https://www.bluetooth.com/specifications/assigned-numbers/">Bluetooth Assigned Numbers</a>,
+     * including metadata that was not covered by the getter methods in this class
+     *
+     * @return raw bytes of stream metadata in Bluetooth LTV format
+     */
+    public @NonNull byte[] getRawMetadata() {
+        return mRawMetadata;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mProgramInfo);
+        out.writeString(mLanguage);
+        out.writeInt(mRawMetadata.length);
+        out.writeByteArray(mRawMetadata);
+    }
+
+    /**
+     * A {@link Parcelable.Creator} to create {@link BluetoothLeAudioContentMetadata} from parcel.
+     * @hide
+     */
+    @SystemApi
+    public static final @NonNull Parcelable.Creator<BluetoothLeAudioContentMetadata> CREATOR =
+            new Parcelable.Creator<BluetoothLeAudioContentMetadata>() {
+                public @NonNull BluetoothLeAudioContentMetadata createFromParcel(
+                        @NonNull Parcel in) {
+                    final String programInfo = in.readString();
+                    final String language = in.readString();
+                    final int rawMetadataLength = in.readInt();
+                    byte[] rawMetadata = new byte[rawMetadataLength];
+                    in.readByteArray(rawMetadata);
+                    return new BluetoothLeAudioContentMetadata(programInfo, language, rawMetadata);
+                }
+
+                public @NonNull BluetoothLeAudioContentMetadata[] newArray(int size) {
+                    return new BluetoothLeAudioContentMetadata[size];
+                }
+            };
+
+    /**
+     * Construct a {@link BluetoothLeAudioContentMetadata} from raw bytes.
+     *
+     * The byte array will be parsed and values for each getter will be populated
+     *
+     * Raw metadata cannot be set using builder in order to maintain raw bytes and getter value
+     * consistency
+     *
+     * @param rawBytes raw bytes of stream metadata in Bluetooth LTV format
+     * @return parsed {@link BluetoothLeAudioContentMetadata} object
+     * @throws IllegalArgumentException if <var>rawBytes</var> is null or when the raw bytes cannot
+     * be parsed to build the object
+     * @hide
+     */
+    @SystemApi
+    public static @NonNull BluetoothLeAudioContentMetadata fromRawBytes(@NonNull byte[] rawBytes) {
+        if (rawBytes == null) {
+            throw new IllegalArgumentException("Raw bytes cannot be null");
+        }
+        return null;
+    }
+
+    /**
+     * Builder for {@link BluetoothLeAudioContentMetadata}.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+        private String mProgramInfo = null;
+        private String mLanguage = null;
+        private byte[] mRawMetadata = null;
+
+        /**
+         * Create an empty builder
+         *
+         * @hide
+         */
+        @SystemApi
+        public Builder() {}
+
+        /**
+         * Create a builder with copies of information from original object.
+         *
+         * @param original original object
+         * @hide
+         */
+        @SystemApi
+        public Builder(@NonNull BluetoothLeAudioContentMetadata original) {
+            mProgramInfo = original.getProgramInfo();
+            mLanguage = original.getLanguage();
+            mRawMetadata = original.getRawMetadata();
+        }
+
+        /**
+         * Set the title and/or summary of Audio Stream content in UTF-8 format.
+         *
+         * @param programInfo  title and/or summary of Audio Stream content in UTF-8 format, null
+         *                     if this metadata does not exist
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setProgramInfo(@Nullable String programInfo) {
+            mProgramInfo = programInfo;
+            return this;
+        }
+
+        /**
+         * Set language of the audio stream in 3-byte, lower case language code as defined in
+         * ISO 639-3.
+         *
+         * @return ISO 639-3 formatted language code, null if this metadata does not exist
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setLanguage(@Nullable String language) {
+            mLanguage = language;
+            return this;
+        }
+
+        /**
+         * Build {@link BluetoothLeAudioContentMetadata}.
+         *
+         * @return constructed {@link BluetoothLeAudioContentMetadata}
+         * @throws IllegalArgumentException if the object cannot be built
+         * @hide
+         */
+        @SystemApi
+        public @NonNull BluetoothLeAudioContentMetadata build() {
+            if (mRawMetadata == null) {
+                mRawMetadata = new byte[0];
+            }
+            return new BluetoothLeAudioContentMetadata(mProgramInfo, mLanguage, mRawMetadata);
+        }
+    }
+}
diff --git a/framework/java/android/bluetooth/BluetoothLeBroadcast.java b/framework/java/android/bluetooth/BluetoothLeBroadcast.java
index fed9f91..4537cc6 100644
--- a/framework/java/android/bluetooth/BluetoothLeBroadcast.java
+++ b/framework/java/android/bluetooth/BluetoothLeBroadcast.java
@@ -16,270 +16,412 @@
 
 package android.bluetooth;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
 import android.content.Context;
 import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
- * This class provides the public APIs to control the Bluetooth LE Broadcast Source profile.
+ * This class provides the public APIs to control the BAP Broadcast Source profile.
  *
- * <p>BluetoothLeBroadcast is a proxy object for controlling the Bluetooth LE Broadcast
- * Source Service via IPC. Use {@link BluetoothAdapter#getProfileProxy}
- * to get the BluetoothLeBroadcast proxy object.
+ * <p>BluetoothLeBroadcast is a proxy object for controlling the Bluetooth LE Broadcast Source
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the BluetoothLeBroadcast
+ * proxy object.
  *
  * @hide
  */
-public final class BluetoothLeBroadcast implements BluetoothProfile {
+@SystemApi
+public final class BluetoothLeBroadcast implements AutoCloseable, BluetoothProfile {
     private static final String TAG = "BluetoothLeBroadcast";
     private static final boolean DBG = true;
-    private static final boolean VDBG = false;
 
     /**
-     * Constants used by the LE Audio Broadcast profile for the Broadcast state
-     *
+     * Interface for receiving events related to Broadcast Source
      * @hide
      */
-    @IntDef(prefix = {"LE_AUDIO_BROADCAST_STATE_"}, value = {
-      LE_AUDIO_BROADCAST_STATE_DISABLED,
-      LE_AUDIO_BROADCAST_STATE_ENABLING,
-      LE_AUDIO_BROADCAST_STATE_ENABLED,
-      LE_AUDIO_BROADCAST_STATE_DISABLING,
-      LE_AUDIO_BROADCAST_STATE_PLAYING,
-      LE_AUDIO_BROADCAST_STATE_NOT_PLAYING
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface LeAudioBroadcastState {}
-
-    /**
-     * Indicates that LE Audio Broadcast mode is currently disabled
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_STATE_DISABLED = 10;
-
-    /**
-     * Indicates that LE Audio Broadcast mode is being enabled
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_STATE_ENABLING = 11;
-
-    /**
-     * Indicates that LE Audio Broadcast mode is currently enabled
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_STATE_ENABLED = 12;
-    /**
-     * Indicates that LE Audio Broadcast mode is being disabled
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_STATE_DISABLING = 13;
-
-    /**
-     * Indicates that an LE Audio Broadcast mode is currently playing
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_STATE_PLAYING = 14;
-
-    /**
-     * Indicates that LE Audio Broadcast is currently not playing
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_STATE_NOT_PLAYING = 15;
-
-    /**
-     * Constants used by the LE Audio Broadcast profile for encryption key length
-     *
-     * @hide
-     */
-    @IntDef(prefix = {"LE_AUDIO_BROADCAST_ENCRYPTION_KEY_"}, value = {
-      LE_AUDIO_BROADCAST_ENCRYPTION_KEY_32BIT,
-      LE_AUDIO_BROADCAST_ENCRYPTION_KEY_128BIT
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface LeAudioEncryptionKeyLength {}
-
-    /**
-     * Indicates that the LE Audio Broadcast encryption key size is 32 bits.
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_ENCRYPTION_KEY_32BIT = 16;
-
-    /**
-     * Indicates that the LE Audio Broadcast encryption key size is 128 bits.
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_ENCRYPTION_KEY_128BIT = 17;
-
-    /**
-     * Interface for receiving events related to broadcasts
-     */
+    @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_SYSTEM_POLICY,
+                BluetoothStatusCodes.ERROR_HARDWARE_GENERIC,
+                BluetoothStatusCodes.ERROR_BAD_PARAMETERS,
+                BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES,
+                BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_CODE,
+                BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_BROADCAST_ID,
+                BluetoothStatusCodes.ERROR_LE_CONTENT_METADATA_INVALID_PROGRAM_INFO,
+                BluetoothStatusCodes.ERROR_LE_CONTENT_METADATA_INVALID_LANGUAGE,
+                BluetoothStatusCodes.ERROR_LE_CONTENT_METADATA_INVALID_OTHER,
+        })
+        @interface Reason {}
+
         /**
-         * Called when broadcast state has changed
+         * Callback invoked when broadcast is started, but audio may not be playing.
          *
-         * @param prevState broadcast state before the change
-         * @param newState broadcast state after the change
+         * Caller should wait for
+         * {@link #onBroadcastMetadataChanged(int, BluetoothLeBroadcastMetadata)}
+         * for the updated metadata
+         *
+         * @param reason for broadcast start
+         * @param broadcastId as defined by the Basic Audio Profile
+         * @hide
          */
-        @LeAudioBroadcastState
-        void onBroadcastStateChange(int prevState, int newState);
+        @SystemApi
+        void onBroadcastStarted(@Reason int reason, int broadcastId);
+
         /**
-         * Called when encryption key has been updated
+         * Callback invoked when broadcast failed to start
          *
-         * @param success true if the key was updated successfully, false otherwise
+         * @param reason for broadcast start failure
+         * @hide
          */
-        void onEncryptionKeySet(boolean success);
+        @SystemApi
+        void onBroadcastStartFailed(@Reason int reason);
+
+        /**
+         * Callback invoked when broadcast is stopped
+         *
+         * @param reason for broadcast stop
+         * @hide
+         */
+        @SystemApi
+        void onBroadcastStopped(@Reason int reason, int broadcastId);
+
+        /**
+         * Callback invoked when broadcast failed to stop
+         *
+         * @param reason for broadcast stop failure
+         * @hide
+         */
+        @SystemApi
+        void onBroadcastStopFailed(@Reason int reason);
+
+        /**
+         * Callback invoked when broadcast audio is playing
+         *
+         * @param reason for playback start
+         * @param broadcastId as defined by the Basic Audio Profile
+         * @hide
+         */
+        @SystemApi
+        void onPlaybackStarted(@Reason int reason, int broadcastId);
+
+        /**
+         * Callback invoked when broadcast audio is not playing
+         *
+         * @param reason for playback stop
+         * @param broadcastId as defined by the Basic Audio Profile
+         * @hide
+         */
+        @SystemApi
+        void onPlaybackStopped(@Reason int reason, int broadcastId);
+
+        /**
+         * Callback invoked when encryption is enabled
+         *
+         * @param reason for encryption enable
+         * @param broadcastId as defined by the Basic Audio Profile
+         * @hide
+         */
+        @SystemApi
+        void onBroadcastUpdated(@Reason int reason, int broadcastId);
+
+        /**
+         * Callback invoked when Broadcast Source failed to update
+         *
+         * @param reason for update failure
+         * @param broadcastId as defined by the Basic Audio Profile
+         * @hide
+         */
+        @SystemApi
+        void onBroadcastUpdateFailed(int reason, int broadcastId);
+
+        /**
+         * Callback invoked when Broadcast Source metadata is updated
+         *
+         * @param metadata updated Broadcast Source metadata
+         * @param broadcastId as defined by the Basic Audio Profile
+         * @hide
+         */
+        @SystemApi
+        void onBroadcastMetadataChanged(int broadcastId,
+                @NonNull BluetoothLeBroadcastMetadata metadata);
     }
 
     /**
-     * Create a BluetoothLeBroadcast proxy object for interacting with the local
-     * LE Audio Broadcast Source service.
+     * Create a BluetoothLeBroadcast proxy object for interacting with the local LE Audio Broadcast
+     * Source service.
      *
+     * @param context  for to operate this API class
+     * @param listener listens for service callbacks across binder
      * @hide
      */
-    /*package*/ BluetoothLeBroadcast(Context context,
-                                     BluetoothProfile.ServiceListener listener) {
-    }
+    /*package*/ BluetoothLeBroadcast(Context context, BluetoothProfile.ServiceListener listener) {}
 
     /**
-     * Not supported since LE Audio Broadcasts do not establish a connection
-     *
-     * @throws UnsupportedOperationException
+     * Not supported since LE Audio Broadcasts do not establish a connection.
      *
      * @hide
      */
     @Override
-    public int getConnectionState(BluetoothDevice device) {
-        throw new UnsupportedOperationException(
-                   "LE Audio Broadcasts are not connection-oriented.");
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public int getConnectionState(@NonNull BluetoothDevice device) {
+        throw new UnsupportedOperationException("LE Audio Broadcasts are not connection-oriented.");
     }
 
     /**
-     * Not supported since LE Audio Broadcasts do not establish a connection
-     *
-     * @throws UnsupportedOperationException
+     * Not supported since LE Audio Broadcasts do not establish a connection.
      *
      * @hide
      */
     @Override
-    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
-        throw new UnsupportedOperationException(
-                   "LE Audio Broadcasts are not connection-oriented.");
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
+            @NonNull int[] states) {
+        throw new UnsupportedOperationException("LE Audio Broadcasts are not connection-oriented.");
     }
 
     /**
-     * Not supported since LE Audio Broadcasts do not establish a connection
-     *
-     * @throws UnsupportedOperationException
+     * Not supported since LE Audio Broadcasts do not establish a connection.
      *
      * @hide
      */
     @Override
-    public List<BluetoothDevice> getConnectedDevices() {
-        throw new UnsupportedOperationException(
-                   "LE Audio Broadcasts are not connection-oriented.");
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public @NonNull List<BluetoothDevice> getConnectedDevices() {
+        throw new UnsupportedOperationException("LE Audio Broadcasts are not connection-oriented.");
     }
 
     /**
-     * Enable LE Audio Broadcast mode.
+     * Register a {@link Callback} that will be invoked during the operation of this profile.
      *
-     * Generates a new broadcast ID and enables sending of encrypted or unencrypted
-     * isochronous PDUs
+     * 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
      */
-    public int enableBroadcastMode() {
-        if (DBG) log("enableBroadcastMode");
-        return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED;
+    @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");
+        }
+        log("registerCallback");
+        throw new UnsupportedOperationException("Not Implemented");
     }
 
     /**
-     * Disable LE Audio Broadcast mode.
+     * 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
      */
-    public int disableBroadcastMode() {
+    @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");
+        }
+        log("unregisterCallback");
+        throw new UnsupportedOperationException("Not Implemented");
+    }
+
+    /**
+     * Start broadcasting to nearby devices using <var>broadcastCode</var> and
+     * <var>contentMetadata</var>
+     *
+     * Encryption will be enabled when <var>broadcastCode</var> is not null.
+     *
+     * <p>As defined in Volume 3, Part C, Section 3.2.6 of Bluetooth Core Specification, Version
+     * 5.3, Broadcast Code is used to encrypt a broadcast audio stream.
+     * <p>It must be a UTF-8 string that has at least 4 octets and should not exceed 16 octets.
+     *
+     * If the provided <var>broadcastCode</var> is non-null and does not meet the above
+     * requirements, encryption will fail to enable with reason code
+     * {@link BluetoothStatusCodes#ERROR_LE_BROADCAST_INVALID_CODE}
+     *
+     * Caller can set content metadata such as program information string in
+     * <var>contentMetadata</var>
+     *
+     * On success, {@link Callback#onBroadcastStarted(int, int)} will be invoked with
+     * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST} reason code.
+     * On failure, {@link Callback#onBroadcastStartFailed(int)} will be invoked  with reason code.
+     *
+     * In particular, when the number of Broadcast Sources reaches
+     * {@link #getMaximumNumberOfBroadcast()}, this method will fail with
+     * {@link BluetoothStatusCodes#ERROR_LOCAL_NOT_ENOUGH_RESOURCES}
+     *
+     * After broadcast is started,
+     * {@link Callback#onBroadcastMetadataChanged(int, BluetoothLeBroadcastMetadata)}
+     * will be invoked to expose the latest Broadcast Group metadata that can be shared out of band
+     * to set up Broadcast Sink without scanning.
+     *
+     * Alternatively, one can also get the latest Broadcast Source meta via
+     * {@link #getAllBroadcastMetadata()}
+     *
+     * @param contentMetadata metadata for the default Broadcast subgroup
+     * @param broadcastCode Encryption will be enabled when <var>broadcastCode</var> is not null
+     * @throws IllegalArgumentException if <var>contentMetadata</var> is null
+     * @throws IllegalStateException if callback was not registered
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public void startBroadcast(@NonNull BluetoothLeAudioContentMetadata contentMetadata,
+            @Nullable byte[] broadcastCode) {
+        if (DBG) log("startBroadcasting");
+    }
+
+    /**
+     * Update the broadcast with <var>broadcastId</var> with new <var>contentMetadata</var>
+     *
+     * On success, {@link Callback#onBroadcastUpdated(int, int)} will be invoked with reason code
+     * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}.
+     * On failure, {@link Callback#onBroadcastUpdateFailed(int, int)} will be invoked with reason
+     * code
+     *
+     * @param broadcastId broadcastId as defined by the Basic Audio Profile
+     * @param contentMetadata updated metadata for the default Broadcast subgroup
+     * @throws IllegalStateException if callback was not registered
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public void updateBroadcast(int broadcastId,
+            @NonNull BluetoothLeAudioContentMetadata contentMetadata) {
+
+    }
+
+    /**
+     * Stop broadcasting.
+     *
+     * On success, {@link Callback#onBroadcastStopped(int, int)} will be invoked with reason code
+     * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST} and the <var>broadcastId</var>
+     * On failure, {@link Callback#onBroadcastStopFailed(int)} will be invoked with reason code
+     *
+     * @param broadcastId as defined by the Basic Audio Profile
+     * @throws IllegalStateException if callback was not registered
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public void stopBroadcast(int broadcastId) {
         if (DBG) log("disableBroadcastMode");
-        return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED;
     }
 
     /**
-     * Get the current LE Audio broadcast state
+     * Return true if audio is being broadcasted on the Broadcast Source as identified by the
+     * <var>broadcastId</var>
      *
+     * @param broadcastId as defined in the Basic Audio Profile
+     * @return true if audio is being broadcasted
      * @hide
      */
-    @LeAudioBroadcastState
-    public int getBroadcastState() {
-        if (DBG) log("getBroadcastState");
-        return LE_AUDIO_BROADCAST_STATE_DISABLED;
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public boolean isPlaying(int broadcastId) {
+        return false;
     }
 
     /**
-     * Enable LE Audio broadcast encryption
+     * Get {@link BluetoothLeBroadcastMetadata} for all Broadcast Groups currently running on
+     * this device
      *
-     * @param keyLength if useExisting is true, this specifies the length of the key that should
-     *                  be generated
-     * @param useExisting true, if an existing key should be used
-     *                    false, if a new key should be generated
-     *
+     * @return list of {@link BluetoothLeBroadcastMetadata}
      * @hide
      */
-    @LeAudioEncryptionKeyLength
-    public int enableEncryption(boolean useExisting, int keyLength) {
-        if (DBG) log("enableEncryption useExisting=" + useExisting + " keyLength=" + keyLength);
-        return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_ENABLE_ENCRYPTION_FAILED;
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public @NonNull List<BluetoothLeBroadcastMetadata> getAllBroadcastMetadata() {
+        return Collections.emptyList();
     }
 
     /**
-     * Disable LE Audio broadcast encryption
-     *
-     * @param removeExisting true, if the existing key should be removed
-     *                       false, otherwise
-     *
+     * Get the maximum number of broadcast groups supported on this device
+     * @return maximum number of broadcast groups supported on this device
      * @hide
      */
-    public int disableEncryption(boolean removeExisting) {
-        if (DBG) log("disableEncryption removeExisting=" + removeExisting);
-        return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED;
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public int getMaximumNumberOfBroadcast() {
+        return 1;
     }
 
     /**
-     * Enable or disable LE Audio broadcast encryption
-     *
-     * @param key use the provided key if non-null, generate a new key if null
-     * @param keyLength 0 if encryption is disabled, 4 bytes (low security),
-     *                  16 bytes (high security)
-     *
+     * {@inheritDoc}
      * @hide
      */
-    @LeAudioEncryptionKeyLength
-    public int setEncryptionKey(byte[] key, int keyLength) {
-        if (DBG) log("setEncryptionKey key=" + key + " keyLength=" + keyLength);
-        return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_ENCRYPTION_KEY_FAILED;
-    }
-
-
-    /**
-     * Get the encryption key that was set before
-     *
-     * @return encryption key as a byte array or null if no encryption key was set
-     *
-     * @hide
-     */
-    public byte[] getEncryptionKey() {
-        if (DBG) log("getEncryptionKey");
-        return null;
-    }
+    @Override
+    public void close() throws Exception {}
 
     private static void log(String msg) {
         Log.d(TAG, msg);
diff --git a/framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java b/framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java
new file mode 100644
index 0000000..81f5d18
--- /dev/null
+++ b/framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java
@@ -0,0 +1,738 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
+import android.bluetooth.annotations.RequiresBluetoothScanPermission;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanSettings;
+import android.content.Context;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * This class provides the public APIs for the LE Audio Broadcast Assistant role, which implements
+ * client side control points for Broadcast Audio Scan Service (BASS).
+ *
+ * <p>An LE Audio Broadcast Assistant can help a Broadcast Sink to scan for available Broadcast
+ * Sources. The Broadcast Sink achieves this by offloading the scan to a Broadcast Assistant.
+ * This is facilitated by the Broadcast Audio Scan Service (BASS). A BASS server is a GATT
+ * server that is part of the Scan Delegator on a Broadcast Sink. A BASS client instead runs on
+ * the Broadcast Assistant.
+ *
+ * <p>Once a GATT connection is established between the BASS client and the BASS server, the
+ * Broadcast Sink can offload the scans to the Broadcast Assistant. Upon finding new Broadcast
+ * Sources, the Broadcast Assistant then notifies the Broadcast Sink about these over the
+ * established GATT connection. The Scan Delegator on the Broadcast Sink can also notify the
+ * Assistant about changes such as addition and removal of Broadcast Sources.
+ *
+ * In the context of this class, BASS server will be addressed as Broadcast Sink and BASS client
+ * will be addressed as Broadcast Assistant.
+ *
+ * <p>BluetoothLeBroadcastAssistant is a proxy object for controlling the Broadcast Assistant
+ * service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the
+ * BluetoothLeBroadcastAssistant proxy object.
+ *
+ * @hide
+ */
+@SystemApi
+public final class BluetoothLeBroadcastAssistant implements BluetoothProfile {
+    private static final String TAG = "BluetoothLeBroadcastAssistant";
+    private static final boolean DBG = true;
+
+    /**
+     * This class provides a set of callbacks that are invoked when scanning for Broadcast Sources
+     * is offloaded to a Broadcast Assistant.
+     *
+     * @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_HARDWARE_GENERIC,
+                BluetoothStatusCodes.ERROR_LE_BROADCAST_ASSISTANT_DUPLICATE_ADDITION,
+                BluetoothStatusCodes.ERROR_BAD_PARAMETERS,
+                BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR,
+                BluetoothStatusCodes.ERROR_REMOTE_NOT_ENOUGH_RESOURCES,
+                BluetoothStatusCodes.ERROR_LE_BROADCAST_ASSISTANT_INVALID_SOURCE_ID,
+                BluetoothStatusCodes.ERROR_ALREADY_IN_TARGET_STATE,
+                BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED,
+        })
+        @interface Reason {}
+
+        /**
+         * Callback invoked when the implementation started searching for nearby Broadcast Sources.
+         *
+         * @param reason reason code on why search has started
+         * @hide
+         */
+        @SystemApi
+        void onSearchStarted(@Reason int reason);
+
+        /**
+         * Callback invoked when the implementation failed to start searching for nearby broadcast
+         * sources.
+         *
+         * @param reason reason for why search failed to start
+         * @hide
+         */
+        @SystemApi
+        void onSearchStartFailed(@Reason int reason);
+
+        /**
+         * Callback invoked when the implementation stopped searching for nearby Broadcast Sources.
+         *
+         * @param reason reason code on why search has stopped
+         * @hide
+         */
+        @SystemApi
+        void onSearchStopped(@Reason int reason);
+
+        /**
+         * Callback invoked when the implementation failed to stop searching for nearby broadcast
+         * sources.
+         *
+         * @param reason for why search failed to start
+         * @hide
+         */
+        @SystemApi
+        void onSearchStopFailed(@Reason int reason);
+
+        /**
+         * Callback invoked when a new Broadcast Source is found together with the
+         * {@link BluetoothLeBroadcastMetadata}.
+         *
+         * @param source {@link BluetoothLeBroadcastMetadata} representing a Broadcast Source
+         * @hide
+         */
+        @SystemApi
+        void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source);
+
+        /**
+         * Callback invoked when a new Broadcast Source has been successfully added to the
+         * Broadcast Sink.
+         *
+         * Broadcast audio stream may not have been started after this callback, the caller need
+         * to monitor
+         * {@link #onReceiveStateChanged(BluetoothDevice, int, BluetoothLeBroadcastReceiveState)}
+         * to see if synchronization with Broadcast Source is successful
+         *
+         * When <var>isGroupOp</var> is true when
+         * {@link #addSource(BluetoothDevice, BluetoothLeBroadcastMetadata, boolean)}
+         * is called, each Broadcast Sink device in the coordinated set will trigger and individual
+         * update
+         *
+         * A new source could be added by the Broadcast Sink itself or other Broadcast Assistants
+         * connected to the Broadcast Sink and in this case the reason code will be
+         * {@link BluetoothStatusCodes#REASON_REMOTE_REQUEST}
+         *
+         * @param sink Broadcast Sink device on which a new Broadcast Source has been added
+         * @param sourceId source ID as defined in the BASS specification
+         * @param reason reason of source addition
+         * @hide
+         */
+        @SystemApi
+        void onSourceAdded(@NonNull BluetoothDevice sink, @Reason int sourceId,
+                @Reason int reason);
+
+        /**
+         * Callback invoked when the new Broadcast Source failed to be added to the Broadcast Sink.
+         *
+         * @param sink Broadcast Sink device on which a new Broadcast Source has been added
+         * @param source metadata representation of the Broadcast Source
+         * @param reason reason why the addition has failed
+         * @hide
+         */
+        @SystemApi
+        void onSourceAddFailed(@NonNull BluetoothDevice sink,
+                @NonNull BluetoothLeBroadcastMetadata source, @Reason int reason);
+
+        /**
+         * Callback invoked when an existing Broadcast Source within a Broadcast Sink has been
+         * modified.
+         *
+         * Actual state after the modification will be delivered via the next
+         * {@link Callback#onReceiveStateChanged(BluetoothDevice, int,
+         * BluetoothLeBroadcastReceiveState)}
+         * callback.
+         *
+         * A source could be modified by the Broadcast Sink itself or other Broadcast Assistants
+         * connected to the Broadcast Sink and in this case the reason code will be
+         * {@link BluetoothStatusCodes#REASON_REMOTE_REQUEST}
+         *
+         * @param sink Broadcast Sink device on which a Broadcast Source has been modified
+         * @param sourceId source ID as defined in the BASS specification
+         * @param reason reason of source modification
+         * @hide
+         */
+        @SystemApi
+        void onSourceModified(@NonNull BluetoothDevice sink, int sourceId, @Reason int reason);
+
+        /**
+         * Callback invoked when the Broadcast Assistant failed to modify an existing Broadcast
+         * Source on a Broadcast Sink.
+         *
+         * @param sink Broadcast Sink device on which a Broadcast Source has been modified
+         * @param sourceId source ID as defined in the BASS specification
+         * @param reason reason why the modification has failed
+         * @hide
+         */
+        @SystemApi
+        void onSourceModifyFailed(@NonNull BluetoothDevice sink, int sourceId, @Reason int reason);
+
+        /**
+         * Callback invoked when a Broadcast Source has been successfully removed from the
+         * Broadcast Sink.
+         *
+         * No more update for the source ID via
+         * {@link Callback#onReceiveStateChanged(BluetoothDevice, int,
+         * BluetoothLeBroadcastReceiveState)}
+         * after this callback.
+         *
+         * A source could be removed by the Broadcast Sink itself or other Broadcast Assistants
+         * connected to the Broadcast Sink and in this case the reason code will be
+         * {@link BluetoothStatusCodes#REASON_REMOTE_REQUEST}
+         *
+         * @param sink Broadcast Sink device from which a Broadcast Source has been removed
+         * @param sourceId source ID as defined in the BASS specification
+         * @param reason  reason why the Broadcast Source was removed
+         * @hide
+         */
+        @SystemApi
+        void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId, @Reason int reason);
+
+        /**
+         * Callback invoked when the Broadcast Assistant failed to remove an existing Broadcast
+         * Source on a Broadcast Sink.
+         *
+         * @param sink Broadcast Sink device on which a Broadcast Source was to be removed
+         * @param sourceId source ID as defined in the BASS specification
+         * @param reason reason why the modification has failed
+         * @hide
+         */
+        @SystemApi
+        void onSourceRemoveFailed(@NonNull BluetoothDevice sink, int sourceId, @Reason int reason);
+
+        /**
+         * Callback invoked when the Broadcast Receive State information of a Broadcast Sink device
+         * changes.
+         *
+         * @param sink  BASS server device that is also a Broadcast Sink device
+         * @param sourceId source ID as defined in the BASS specification
+         * @param state latest state information between the Broadcast Sink and a Broadcast Source
+         * @hide
+         */
+        @SystemApi
+        void onReceiveStateChanged(@NonNull BluetoothDevice sink, int sourceId,
+                @NonNull BluetoothLeBroadcastReceiveState state);
+    }
+
+    /**
+     * Intent used to broadcast the change in connection state of devices via Broadcast Audio Scan
+     * Service (BASS). Please note that in a coordinated set, each set member will connect via BASS
+     * individually. Group operations on a single set member will propagate to the entire set.
+     *
+     * For example, 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. If both devices
+     * belongs to on Coordinated Set, group operation on one of them will affect both devices.
+     *
+     * <p>This intent will have 3 extras:
+     * <ul>
+     * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+     * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+     * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+     * </ul>
+     *
+     * <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(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_CONNECTION_STATE_CHANGED =
+            "android.bluetooth.action.CONNECTION_STATE_CHANGED";
+
+    /**
+     * Create a new instance of an LE Audio Broadcast Assistant.
+     *
+     * @hide
+     */
+    /*package*/ BluetoothLeBroadcastAssistant(
+            @NonNull Context context, @NonNull ServiceListener listener) {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    @Override
+    public @BluetoothProfile.BtProfileState int getConnectionState(@NonNull BluetoothDevice sink) {
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    @Override
+    public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
+            @NonNull int[] states) {
+        return Collections.emptyList();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    @Override
+    @NonNull
+    public List<BluetoothDevice> getConnectedDevices() {
+        return Collections.emptyList();
+    }
+
+    /**
+     * Set connection policy of the profile.
+     *
+     * <p> The device should already be paired. Connection policy can be one of {
+     * @link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
+        return false;
+    }
+
+    /**
+     * Get the connection policy of the profile.
+     *
+     * <p> The connection policy can be any of:
+     * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Bluetooth device
+     * @return connection policy of the device
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
+        return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+    }
+
+    /**
+     * 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. 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");
+        }
+        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");
+        }
+        log("unregisterCallback");
+        throw new UnsupportedOperationException("Not Implemented");
+    }
+
+    /**
+     * Search for LE Audio Broadcast Sources on behalf of all devices connected via Broadcast Audio
+     * Scan Service, filtered by <var>filters</var>.
+     *
+     * On success, {@link Callback#onSearchStarted(int)} will be called with reason code
+     * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}.
+     *
+     * On failure, {@link Callback#onSearchStartFailed(int)} will be called with reason code
+     *
+     * The implementation will also synchronize with discovered Broadcast Sources and get their
+     * metadata before passing the Broadcast Source metadata back to the application using {@link
+     * Callback#onSourceFound(BluetoothLeBroadcastMetadata)}.
+     *
+     * Please disconnect the Broadcast Sink's BASS server by calling
+     * {@link #setConnectionPolicy(BluetoothDevice, int)} with
+     * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN} if you do not want the Broadcast Sink
+     * to receive notifications about this search before calling this method.
+     *
+     * App must also have
+     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
+     * permission in order to get results.
+     *
+     * <var>filters</var> will be AND'ed with internal filters in the implementation and
+     * {@link ScanSettings} will be managed by the implementation.
+     *
+     * @param filters {@link ScanFilter}s for finding exact Broadcast Source, if no filter is
+     *               needed, please provide an empty list instead
+     * @throws IllegalArgumentException when <var>filters</var> argument is null
+     * @throws IllegalStateException when no callback is registered
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothScanPermission
+    @RequiresBluetoothLocationPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_SCAN,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public void startSearchingForSources(@NonNull List<ScanFilter> filters) {
+        log("searchForBroadcastSources");
+        if (filters == null) {
+            throw new IllegalArgumentException("filters can be empty, but not null");
+        }
+        throw new UnsupportedOperationException("Not Implemented");
+    }
+
+    /**
+     * Stops an ongoing search for nearby Broadcast Sources.
+     *
+     * On success, {@link Callback#onSearchStopped(int)} will be called with reason code
+     * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}.
+     * On failure, {@link Callback#onSearchStopFailed(int)} will be called with reason code
+     *
+     * @throws IllegalStateException if callback was not registered
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public void stopSearchingForSources() {
+        log("stopSearchingForSources:");
+        throw new UnsupportedOperationException("Not Implemented");
+    }
+
+    /**
+     * Return true if a search has been started by this application.
+     *
+     * @return true if a search has been started by this application
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public boolean isSearchInProgress() {
+        return false;
+    }
+
+    /**
+     * Add a Broadcast Source to the Broadcast Sink.
+     *
+     * Caller can modify <var>sourceMetadata</var> before using it in this method to set a
+     * Broadcast Code, to select a different Broadcast Channel in a Broadcast Source such as channel
+     * with a different language, and so on. What can be modified is listed in the documentation of
+     * {@link #modifySource(BluetoothDevice, int, BluetoothLeBroadcastMetadata)} and can also be
+     * modified after a source is added.
+     *
+     * On success, {@link Callback#onSourceAdded(BluetoothDevice, int, int)} will be invoked with
+     * a <var>sourceID</var> assigned by the Broadcast Sink with reason code
+     * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}. However, this callback only indicates
+     * that the Broadcast Sink has allocated resource to receive audio from the Broadcast Source,
+     * and audio stream may not have started. The caller should then wait for
+     * {@link Callback#onReceiveStateChanged(BluetoothDevice, int,
+     * BluetoothLeBroadcastReceiveState)}
+     * callback to monitor the encryption and audio sync state.
+     *
+     * Note that wrong broadcast code will not prevent the source from being added to the Broadcast
+     * Sink. Caller should modify the current source to correct the broadcast code.
+     *
+     * On failure,
+     * {@link Callback#onSourceAddFailed(BluetoothDevice, BluetoothLeBroadcastMetadata, int)}
+     * will be invoked with the same <var>source</var> metadata and reason code
+     *
+     * When too many sources was added to Broadcast sink, error
+     * {@link BluetoothStatusCodes#ERROR_REMOTE_NOT_ENOUGH_RESOURCES} will be delivered. In this
+     * case, check the capacity of Broadcast sink via
+     * {@link #getMaximumSourceCapacity(BluetoothDevice)} and the current list of sources via
+     * {@link #getAllSources(BluetoothDevice)}.
+     *
+     * Some sources might be added by other Broadcast Assistants and hence was not
+     * in {@link Callback#onSourceAdded(BluetoothDevice, int, int)} callback, but will be updated
+     * via {@link Callback#onReceiveStateChanged(BluetoothDevice, int,
+     * BluetoothLeBroadcastReceiveState)}
+     *
+     * <p>If there are multiple members in the coordinated set the sink belongs to, and isGroupOp is
+     * set to true, the Broadcast Source will be added to each sink in the coordinated set and a
+     * separate {@link Callback#onSourceAdded} callback will be invoked for each member of the
+     * coordinated set.
+     *
+     * <p>The <var>isGroupOp</var> option is sticky. This means that subsequent operations using
+     * {@link #modifySource(BluetoothDevice, int, BluetoothLeBroadcastMetadata)} and
+     * {@link #removeSource(BluetoothDevice, int)} will act on all devices in the same coordinated
+     * set for the <var>sink</var> and <var>sourceID</var> pair until the <var>sourceId</var> is
+     * removed from the <var>sink</var> by any Broadcast role (could be another remote device).
+     *
+     * <p>When <var>isGroupOp</var> is true, if one Broadcast Sink in a coordinated set
+     * disconnects from this Broadcast Assistant or lost the Broadcast Source, this Broadcast
+     * Assistant will try to add it back automatically to make sure the whole coordinated set
+     * is in the same state.
+     *
+     * @param sink Broadcast Sink to which the Broadcast Source should be added
+     * @param sourceMetadata Broadcast Source metadata to be added to the Broadcast Sink
+     * @param isGroupOp {@code true} if Application wants to perform this operation for all
+     *                  coordinated set members throughout this session. Otherwise, caller
+     *                  would have to add, modify, and remove individual set members.
+     * @throws IllegalArgumentException if <var>sink</var> or <var>source</var> are null
+     * @throws IllegalStateException if callback was not registered
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public void addSource(@NonNull BluetoothDevice sink,
+            @NonNull BluetoothLeBroadcastMetadata sourceMetadata, boolean isGroupOp) {
+        log("addBroadcastSource: " + sourceMetadata + " on " + sink);
+        throw new UnsupportedOperationException("Not Implemented");
+    }
+
+    /**
+     * Modify the Broadcast Source information on a Broadcast Sink.
+     *
+     * One can modify {@link BluetoothLeBroadcastMetadata#getBroadcastCode()} if
+     * {@link BluetoothLeBroadcastReceiveState#getBigEncryptionState()} returns
+     * {@link BluetoothLeBroadcastReceiveState#BIG_ENCRYPTION_STATE_BAD_CODE} or
+     * {@link BluetoothLeBroadcastReceiveState#BIG_ENCRYPTION_STATE_CODE_REQUIRED}
+     *
+     * One can modify {@link BluetoothLeBroadcastMetadata#getPaSyncInterval()} if the Broadcast
+     * Assistant received updated information.
+     *
+     * One can modify {@link BluetoothLeBroadcastChannel#isSelected()} to select different broadcast
+     * channel to listen to (one per {@link BluetoothLeBroadcastSubgroup} or set
+     * {@link BluetoothLeBroadcastSubgroup#isNoChannelPreference()} to leave the choice to the
+     * Broadcast Sink.
+     *
+     * One can modify {@link BluetoothLeBroadcastSubgroup#getContentMetadata()} if the subgroup
+     * metadata changes and the Broadcast Sink need help updating the metadata from Broadcast
+     * Assistant.
+     *
+     * Each of the above modifications can be accepted or rejected by the Broadcast Assistant
+     * implement and/or the Broadcast Sink.
+     *
+     * <p>On success, {@link Callback#onSourceModified(BluetoothDevice, int, int)} will be invoked
+     * with reason code {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}.
+     *
+     * <p>On failure, {@link Callback#onSourceModifyFailed(BluetoothDevice, int, int)} will be
+     * invoked with reason code.
+     *
+     * <p>If there are multiple members in the coordinated set the sink belongs to, and isGroupOp
+     * is set to true during
+     * {@link #addSource(BluetoothDevice, BluetoothLeBroadcastMetadata, boolean)},
+     * the source will be modified on each sink in the coordinated set and a separate
+     * {@link Callback#onSourceModified(BluetoothDevice, int, int)} callback will be invoked for
+     * each member of the coordinated set.
+     *
+     * @param sink Broadcast Sink to which the Broadcast Source should be updated
+     * @param sourceId source ID as delivered in
+     * {@link Callback#onSourceAdded(BluetoothDevice, int, int)}
+     * @param updatedMetadata  updated Broadcast Source metadata to be updated on the Broadcast Sink
+     * @throws IllegalStateException if callback was not registered
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public void modifySource(@NonNull BluetoothDevice sink, int sourceId,
+            @NonNull BluetoothLeBroadcastMetadata updatedMetadata) {
+        log("updateBroadcastSource: " + updatedMetadata + " on " + sink);
+        throw new UnsupportedOperationException("Not Implemented");
+    }
+
+    /**
+     * Removes the Broadcast Source from a Broadcast Sink.
+     *
+     * <p>On success, {@link Callback#onSourceRemoved(BluetoothDevice, int, int)} will be invoked
+     * with reason code {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}.
+     *
+     * <p>On failure, {@link Callback#onSourceRemoveFailed(BluetoothDevice, int, int)} will be
+     * invoked with reason code.
+
+     *
+     * <p>If there are multiple members in the coordinated set the sink belongs to, and isGroupOp is
+     * set to true during
+     * {@link #addSource(BluetoothDevice, BluetoothLeBroadcastMetadata, boolean)},
+     * the source will be removed from each sink in the coordinated set and a separate
+     * {@link Callback#onSourceRemoved(BluetoothDevice, int, int)} callback will be invoked for
+     * each member of the coordinated set.
+     *
+     * @param sink Broadcast Sink from which a Broadcast Source should be removed
+     * @param sourceId source ID as delivered in
+     * {@link Callback#onSourceAdded(BluetoothDevice, int, int)}
+     * @throws IllegalArgumentException when the <var>sink</var> is null
+     * @throws IllegalStateException if callback was not registered
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public void removeSource(@NonNull BluetoothDevice sink, int sourceId) {
+        log("removeBroadcastSource: " + sourceId + " from " + sink);
+        return;
+    }
+
+
+    /**
+     * Get information about all Broadcast Sources that a Broadcast Sink knows about.
+     *
+     * @param sink Broadcast Sink from which to get all Broadcast Sources
+     * @return the list of Broadcast Receive State {@link BluetoothLeBroadcastReceiveState}
+     *         stored in the Broadcast Sink
+     * @throws IllegalArgumentException when <var>sink</var> is null
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public @NonNull List<BluetoothLeBroadcastReceiveState> getAllSources(
+            @NonNull BluetoothDevice sink) {
+        return Collections.emptyList();
+    }
+
+    /**
+     * Get maximum number of sources that can be added to this Broadcast Sink.
+     *
+     * @param sink Broadcast Sink device
+     * @return maximum number of sources that can be added to this Broadcast Sink
+     * @throws IllegalArgumentException when <var>sink</var> is null
+     * @hide
+     */
+    @SystemApi
+    public int getMaximumSourceCapacity(@NonNull BluetoothDevice sink) {
+        return 0;
+    }
+
+    private static void log(@NonNull String msg) {
+        if (DBG) {
+            Log.d(TAG, msg);
+        }
+    }
+}
diff --git a/framework/java/android/bluetooth/BluetoothLeBroadcastAssistantCallback.java b/framework/java/android/bluetooth/BluetoothLeBroadcastAssistantCallback.java
deleted file mode 100644
index c6d161e..0000000
--- a/framework/java/android/bluetooth/BluetoothLeBroadcastAssistantCallback.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.bluetooth.le.ScanResult;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * This class provides a set of callbacks that are invoked when scanning for Broadcast Sources is
- * offloaded to a Broadcast Assistant.
- *
- * <p>An LE Audio Broadcast Assistant can help a Broadcast Sink to scan for available Broadcast
- * Sources. The Broadcast Sink achieves this by offloading the scan to a Broadcast Assistant. This
- * is facilitated by the Broadcast Audio Scan Service (BASS). A BASS server is a GATT server that is
- * part of the Scan Delegator on a Broadcast Sink. A BASS client instead runs on the Broadcast
- * Assistant.
- *
- * <p>Once a GATT connection is established between the BASS client and the BASS server, the
- * Broadcast Sink can offload the scans to the Broadcast Assistant. Upon finding new Broadcast
- * Sources, the Broadcast Assistant then notifies the Broadcast Sink about these over the
- * established GATT connection. The Scan Delegator on the Broadcast Sink can also notify the
- * Assistant about changes such as addition and removal of Broadcast Sources.
- *
- * @hide
- */
-public abstract class BluetoothLeBroadcastAssistantCallback {
-
-    /**
-     * Broadcast Audio Scan Service (BASS) codes returned by a BASS Server
-     *
-     * @hide
-     */
-    @IntDef(
-            prefix = "BASS_STATUS_",
-            value = {
-                BASS_STATUS_SUCCESS,
-                BASS_STATUS_FAILURE,
-                BASS_STATUS_INVALID_GATT_HANDLE,
-                BASS_STATUS_TXN_TIMEOUT,
-                BASS_STATUS_INVALID_SOURCE_ID,
-                BASS_STATUS_COLOCATED_SRC_UNAVAILABLE,
-                BASS_STATUS_INVALID_SOURCE_SELECTED,
-                BASS_STATUS_SOURCE_UNAVAILABLE,
-                BASS_STATUS_DUPLICATE_ADDITION,
-            })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface BassStatus {}
-
-    public static final int BASS_STATUS_SUCCESS = 0x00;
-    public static final int BASS_STATUS_FAILURE = 0x01;
-    public static final int BASS_STATUS_INVALID_GATT_HANDLE = 0x02;
-    public static final int BASS_STATUS_TXN_TIMEOUT = 0x03;
-
-    public static final int BASS_STATUS_INVALID_SOURCE_ID = 0x04;
-    public static final int BASS_STATUS_COLOCATED_SRC_UNAVAILABLE = 0x05;
-    public static final int BASS_STATUS_INVALID_SOURCE_SELECTED = 0x06;
-    public static final int BASS_STATUS_SOURCE_UNAVAILABLE = 0x07;
-    public static final int BASS_STATUS_DUPLICATE_ADDITION = 0x08;
-    public static final int BASS_STATUS_NO_EMPTY_SLOT = 0x09;
-    public static final int BASS_STATUS_INVALID_GROUP_OP = 0x10;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(value = {
-            BluetoothProfile.STATE_CONNECTED,
-            BluetoothProfile.STATE_CONNECTING,
-            BluetoothProfile.STATE_DISCONNECTED,
-            BluetoothProfile.STATE_DISCONNECTING
-    })
-    public @interface ConnectionStateValues {}
-
-    /**
-     * Callback invoked when the connection state for an LE Audio Broadcast Sink changes
-     */
-    public void onConnectionStateChange(@ConnectionStateValues int prevState,
-            @ConnectionStateValues int newState) {}
-
-    /**
-     * Callback invoked when a new LE Audio Broadcast Source is found.
-     *
-     * @param result {@link ScanResult} scan result representing a Broadcast Source
-     */
-    public void onSourceFound(@NonNull ScanResult result) {}
-
-    /**
-     * Callback invoked when the Broadcast Assistant synchronizes with Periodic Advertisements (PAs)
-     * of an LE Audio Broadcast Source.
-     *
-     * @param source the selected Broadcast Source
-     */
-    public void onSourceSelected(
-            @NonNull BluetoothLeBroadcastSourceInfo source, @BassStatus int status) {}
-
-    /**
-     * Callback invoked when the Broadcast Assistant loses synchronization with an LE Audio
-     * Broadcast Source.
-     *
-     * @param source the Broadcast Source with which synchronization was lost
-     */
-    public void onSourceLost(
-            @NonNull BluetoothLeBroadcastSourceInfo source, @BassStatus int status) {}
-
-    /**
-     * Callback invoked when a new LE Audio Broadcast Source has been successfully added to the Scan
-     * Delegator (within a Broadcast Sink, for example).
-     *
-     * @param sink Scan Delegator device on which a new Broadcast Source has been added
-     * @param source the added Broadcast Source
-     */
-    public void onSourceAdded(
-            @NonNull BluetoothDevice sink,
-            @NonNull BluetoothLeBroadcastSourceInfo source,
-            @BassStatus int status) {}
-
-    /**
-     * Callback invoked when an existing LE Audio Broadcast Source within a remote Scan Delegator
-     * has been updated.
-     *
-     * @param sink Scan Delegator device on which a Broadcast Source has been updated
-     * @param source the updated Broadcast Source
-     */
-    public void onSourceUpdated(
-            @NonNull BluetoothDevice sink,
-            @NonNull BluetoothLeBroadcastSourceInfo source,
-            @BassStatus int status) {}
-
-    /**
-     * Callback invoked when an LE Audio Broadcast Source has been successfully removed from the
-     * Scan Delegator (within a Broadcast Sink, for example).
-     *
-     * @param sink Scan Delegator device from which a Broadcast Source has been removed
-     * @param source the removed Broadcast Source
-     */
-    public void onSourceRemoved(
-            @NonNull BluetoothDevice sink,
-            @NonNull BluetoothLeBroadcastSourceInfo source,
-            @BassStatus int status) {}
-}
diff --git a/framework/java/android/bluetooth/BluetoothLeBroadcastChannel.java b/framework/java/android/bluetooth/BluetoothLeBroadcastChannel.java
new file mode 100644
index 0000000..6addc06
--- /dev/null
+++ b/framework/java/android/bluetooth/BluetoothLeBroadcastChannel.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains the Broadcast Isochronous Channel level information as defined in the BASE
+ * structure of the Basic Audio Profile.
+ *
+ * @hide
+ */
+@SystemApi
+public final class BluetoothLeBroadcastChannel implements Parcelable {
+    private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
+
+    private final boolean mIsSelected;
+    private final int mChannelIndex;
+    private final BluetoothLeAudioCodecConfigMetadata mCodecMetadata;
+
+    private BluetoothLeBroadcastChannel(boolean isSelected, int channelIndex,
+            BluetoothLeAudioCodecConfigMetadata codecMetadata) {
+        mIsSelected = isSelected;
+        mChannelIndex = channelIndex;
+        mCodecMetadata = codecMetadata;
+    }
+
+    /**
+     * Return true if the channel is selected by Broadcast Assistant for the Broadcast Sink.
+     *
+     * Used by Broadcast Assistant and Sink, but not Broadcast Source
+     *
+     * @return true if the channel is selected by Broadcast Assistant for the Broadcast Sink
+     * @hide
+     */
+    @SystemApi
+    public boolean isSelected() {
+        return mIsSelected;
+    }
+
+    /**
+     * Get the Broadcast Isochronous Channel index of this Broadcast Channel.
+     *
+     * @return Broadcast Isochronous Channel index
+     * @hide
+     */
+    @SystemApi
+    public int getChannelIndex() {
+        return mChannelIndex;
+    }
+
+    /**
+     * Return the codec specific configuration for this Broadcast Channel.
+     *
+     * @return codec specific configuration for this Broadcast Channel
+     * @hide
+     */
+    @SystemApi
+    public @NonNull BluetoothLeAudioCodecConfigMetadata getCodecMetadata() {
+        return mCodecMetadata;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeBoolean(mIsSelected);
+        out.writeInt(mChannelIndex);
+        out.writeTypedObject(mCodecMetadata, 0);
+    }
+
+    /**
+     * A {@link Parcelable.Creator} to create {@link BluetoothLeBroadcastChannel} from parcel.
+     * @hide
+     */
+    @SystemApi
+    public static final @NonNull Parcelable.Creator<BluetoothLeBroadcastChannel> CREATOR =
+            new Parcelable.Creator<BluetoothLeBroadcastChannel>() {
+                public @NonNull BluetoothLeBroadcastChannel createFromParcel(@NonNull Parcel in) {
+                    BluetoothLeBroadcastChannel.Builder
+                            builder = new BluetoothLeBroadcastChannel.Builder();
+                    builder.setSelected(in.readBoolean());
+                    builder.setChannelIndex(in.readInt());
+                    builder.setCodecMetadata(
+                            in.readTypedObject(BluetoothLeAudioCodecConfigMetadata.CREATOR));
+                    return builder.build();
+                }
+
+                public @NonNull BluetoothLeBroadcastChannel[] newArray(int size) {
+                    return new BluetoothLeBroadcastChannel[size];
+                }
+            };
+
+    /**
+     * Builder for {@link BluetoothLeBroadcastChannel}.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+        private boolean mIsSelected = false;
+        private int mChannelIndex = UNKNOWN_VALUE_PLACEHOLDER;
+        private BluetoothLeAudioCodecConfigMetadata mCodecMetadata = null;
+
+        /**
+         * Create an empty builder.
+         * @hide
+         */
+        @SystemApi
+        public Builder() {}
+
+        /**
+         * Create a builder with copies of information from original object.
+         *
+         * @param original original object
+         * @hide
+         */
+        @SystemApi
+        public Builder(@NonNull BluetoothLeBroadcastChannel original) {
+            mIsSelected = original.isSelected();
+            mChannelIndex = original.getChannelIndex();
+            mCodecMetadata = original.getCodecMetadata();
+        }
+
+        /**
+         * Set if the channel is selected by Broadcast Assistant for the Broadcast Sink.
+         *
+         * Used by Broadcast Assistant and Sink, but not Broadcast Source
+         *
+         * @param isSelected true if the channel is selected by Broadcast Assistant for the
+         *                   Broadcast Sink
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setSelected(boolean isSelected) {
+            mIsSelected = isSelected;
+            return this;
+        }
+
+        /**
+         * Set the Broadcast Isochronous Channel index of this Broadcast Channel.
+         *
+         * @return Broadcast Isochronous Channel index
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setChannelIndex(int channelIndex) {
+            mChannelIndex = channelIndex;
+            return this;
+        }
+
+        /**
+         * Set the codec specific configuration for this Broadcast Channel.
+         *
+         * @param codecMetadata codec specific configuration for this Broadcast Channel
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setCodecMetadata(
+                @NonNull BluetoothLeAudioCodecConfigMetadata codecMetadata) {
+            mCodecMetadata = codecMetadata;
+            return this;
+        }
+
+        /**
+         * Build {@link BluetoothLeBroadcastChannel}.
+         *
+         * @return constructed {@link BluetoothLeBroadcastChannel}
+         * @throws IllegalArgumentException if the object cannot be built
+         * @hide
+         */
+        @SystemApi
+        public @NonNull BluetoothLeBroadcastChannel build() {
+            return new BluetoothLeBroadcastChannel(mIsSelected, mChannelIndex, mCodecMetadata);
+        }
+    }
+}
diff --git a/framework/java/android/bluetooth/BluetoothLeBroadcastMetadata.java b/framework/java/android/bluetooth/BluetoothLeBroadcastMetadata.java
new file mode 100644
index 0000000..1810818
--- /dev/null
+++ b/framework/java/android/bluetooth/BluetoothLeBroadcastMetadata.java
@@ -0,0 +1,486 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class represents a Broadcast Source group and the associated information that is needed
+ * by Broadcast Audio Scan Service (BASS) to set up a Broadcast Sink.
+ *
+ * <p>For example, an LE Audio Broadcast Sink can use the information contained within an instance
+ * of this class to synchronize with an LE Audio Broadcast group in order to listen to audio from
+ * Broadcast subgroup using one or more Broadcast Channels.
+ *
+ * @hide
+ */
+@SystemApi
+public final class BluetoothLeBroadcastMetadata implements Parcelable {
+    // Information needed for adding broadcast Source
+
+    // Optional: Identity address type
+    private final @BluetoothDevice.AddressType int mSourceAddressType;
+    // Optional: Must use identity address
+    private final BluetoothDevice mSourceDevice;
+    private final int mSourceAdvertisingSid;
+    private final int mBroadcastId;
+    private final int mPaSyncInterval;
+    private final boolean mIsEncrypted;
+    private final byte[] mBroadcastCode;
+
+    // BASE structure
+
+    // See Section 7 for description. Range: 0x000000 – 0xFFFFFF Units: μs
+    //All other values: RFU
+    private final int mPresentationDelayMicros;
+    // Number of subgroups used to group BISes present in the BIG
+    //Shall be at least 1, as defined by Rule 1
+    // Sub group info numSubGroup = mSubGroups.length
+    private final List<BluetoothLeBroadcastSubgroup> mSubgroups;
+
+    private BluetoothLeBroadcastMetadata(int sourceAddressType,
+            BluetoothDevice sourceDevice, int sourceAdvertisingSid, int broadcastId,
+            int paSyncInterval, boolean isEncrypted, byte[] broadcastCode, int presentationDelay,
+            List<BluetoothLeBroadcastSubgroup> subgroups) {
+        mSourceAddressType = sourceAddressType;
+        mSourceDevice = sourceDevice;
+        mSourceAdvertisingSid = sourceAdvertisingSid;
+        mBroadcastId = broadcastId;
+        mPaSyncInterval = paSyncInterval;
+        mIsEncrypted = isEncrypted;
+        mBroadcastCode = broadcastCode;
+        mPresentationDelayMicros = presentationDelay;
+        mSubgroups = subgroups;
+    }
+
+    /**
+     * Get the address type of the Broadcast Source.
+     *
+     * Can be either {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC},
+     * {@link BluetoothDevice#ADDRESS_TYPE_RANDOM}
+     *
+     * @return address type of the Broadcast Source
+     * @hide
+     */
+    @SystemApi
+    public @BluetoothDevice.AddressType int getSourceAddressType() {
+        return mSourceAddressType;
+    }
+
+    /**
+     * Get the MAC address of the Broadcast Source, which can be Public Device Address,
+     * Random Device Address, Public Identity Address or Random (static) Identity Address.
+     *
+     * @return MAC address of the Broadcast Source
+     * @hide
+     */
+    @SystemApi
+    public @Nullable BluetoothDevice getSourceDevice() {
+        return mSourceDevice;
+    }
+
+    /**
+     * Get Advertising_SID subfield of the ADI field of the AUX_ADV_IND PDU or the
+     * LL_PERIODIC_SYNC_IND containing the SyncInfo that points to the PA transmitted by the
+     * Broadcast Source.
+     *
+     * @return 1-byte long Advertising_SID of the Broadcast Source
+     * @hide
+     */
+    @SystemApi
+    public int getSourceAdvertisingSid() {
+        return mSourceAdvertisingSid;
+    }
+
+    /**
+     * Broadcast_ID of the Broadcast Source.
+     *
+     * @return 3-byte long Broadcast_ID of the Broadcast Source
+     * @hide
+     */
+    @SystemApi
+    public int getBroadcastId() {
+        return mBroadcastId;
+    }
+
+    /**
+     * Indicated that Periodic Advertising Sync interval is unknown.
+     * @hide
+     */
+    @SystemApi
+    public static final int PA_SYNC_INTERVAL_UNKNOWN = 0xFFFF;
+
+    /**
+     * Get Periodic Advertising Sync interval of the broadcast Source.
+     *
+     * @return Periodic Advertising Sync interval of the broadcast Source,
+     * {@link #PA_SYNC_INTERVAL_UNKNOWN} if unknown
+     * @hide
+     */
+    @SystemApi
+    public int getPaSyncInterval() {
+        return mPaSyncInterval;
+    }
+
+    /**
+     * Return true if the Broadcast Source is encrypted.
+     *
+     * @return true if the Broadcast Source is encrypted
+     * @hide
+     */
+    @SystemApi
+    public boolean isEncrypted() {
+        return mIsEncrypted;
+    }
+
+    /**
+     * Get the Broadcast Code currently set for this Broadcast Source.
+     *
+     * Only needed when encryption is enabled
+     *
+     * <p>As defined in Volume 3, Part C, Section 3.2.6 of Bluetooth Core Specification, Version
+     * 5.3, Broadcast Code is used to encrypt a broadcast audio stream.
+     * <p>It must be a UTF-8 string that has at least 4 octets and should not exceed 16 octets.
+     *
+     * @return Broadcast Code currently set for this Broadcast Source, null if code is not required
+     *         or code is currently unknown
+     * @hide
+     */
+    @SystemApi
+    public @Nullable byte[] getBroadcastCode() {
+        return mBroadcastCode;
+    }
+
+    /**
+     * Get the overall presentation delay in microseconds of this Broadcast Source.
+     *
+     * Presentation delay is defined in Section 7 of the Basic Audio Profile.
+     *
+     * @return presentation delay of this Broadcast Source in microseconds
+     * @hide
+     */
+    @SystemApi
+    public @IntRange(from = 0, to = 0xFFFFFF) int getPresentationDelayMicros() {
+        return mPresentationDelayMicros;
+    }
+
+    /**
+     * Get available subgroups in this broadcast source.
+     *
+     * @return list of subgroups in this broadcast source, which should contain at least one
+     *         subgroup for each Broadcast Source
+     * @hide
+     */
+    @SystemApi
+    public @NonNull List<BluetoothLeBroadcastSubgroup> getSubgroups() {
+        return mSubgroups;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mSourceAddressType);
+        if (mSourceDevice != null) {
+            out.writeInt(1);
+            out.writeTypedObject(mSourceDevice, 0);
+        } else {
+            // zero indicates missing mSourceDevice
+            out.writeInt(0);
+        }
+        out.writeInt(mSourceAdvertisingSid);
+        out.writeInt(mBroadcastId);
+        out.writeInt(mPaSyncInterval);
+        out.writeBoolean(mIsEncrypted);
+        if (mBroadcastCode != null) {
+            out.writeInt(mBroadcastCode.length);
+            out.writeByteArray(mBroadcastCode);
+        } else {
+            // -1 indicates missing broadcast code
+            out.writeInt(-1);
+        }
+        out.writeInt(mPresentationDelayMicros);
+        out.writeTypedList(mSubgroups);
+    }
+
+    /**
+     * A {@link Parcelable.Creator} to create {@link BluetoothLeBroadcastMetadata} from parcel.
+     * @hide
+     */
+    @SystemApi
+    public static final @NonNull Parcelable.Creator<BluetoothLeBroadcastMetadata> CREATOR =
+            new Parcelable.Creator<BluetoothLeBroadcastMetadata>() {
+                public @NonNull BluetoothLeBroadcastMetadata createFromParcel(@NonNull Parcel in) {
+                    Builder builder = new Builder();
+                    final int sourceAddressType = in.readInt();
+                    final int deviceExist = in.readInt();
+                    BluetoothDevice sourceDevice = null;
+                    if (deviceExist == 1) {
+                        sourceDevice = in.readTypedObject(BluetoothDevice.CREATOR);
+                    }
+                    builder.setSourceDevice(sourceDevice, sourceAddressType);
+                    builder.setSourceAdvertisingSid(in.readInt());
+                    builder.setBroadcastId(in.readInt());
+                    builder.setPaSyncInterval(in.readInt());
+                    builder.setEncrypted(in.readBoolean());
+                    final int codeLen = in.readInt();
+                    byte[] broadcastCode = null;
+                    if (codeLen != -1) {
+                        broadcastCode = new byte[codeLen];
+                        if (codeLen > 0) {
+                            in.readByteArray(broadcastCode);
+                        }
+                    }
+                    builder.setBroadcastCode(broadcastCode);
+                    builder.setPresentationDelayMicros(in.readInt());
+                    final List<BluetoothLeBroadcastSubgroup> subgroups = new ArrayList<>();
+                    in.readTypedList(subgroups, BluetoothLeBroadcastSubgroup.CREATOR);
+                    for (BluetoothLeBroadcastSubgroup subgroup : subgroups) {
+                        builder.addSubgroup(subgroup);
+                    }
+                    return builder.build();
+                }
+
+                public @NonNull BluetoothLeBroadcastMetadata[] newArray(int size) {
+                    return new BluetoothLeBroadcastMetadata[size];
+                }
+            };
+
+    private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
+
+    /**
+     * Builder for {@link BluetoothLeBroadcastMetadata}.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+        private @BluetoothDevice.AddressType int mSourceAddressType =
+                BluetoothDevice.ADDRESS_TYPE_UNKNOWN;
+        private BluetoothDevice mSourceDevice = null;
+        private int mSourceAdvertisingSid = UNKNOWN_VALUE_PLACEHOLDER;
+        private int mBroadcastId = UNKNOWN_VALUE_PLACEHOLDER;
+        private int mPaSyncInterval = UNKNOWN_VALUE_PLACEHOLDER;
+        private boolean mIsEncrypted = false;
+        private byte[] mBroadcastCode = null;
+        private int mPresentationDelayMicros = UNKNOWN_VALUE_PLACEHOLDER;
+        private List<BluetoothLeBroadcastSubgroup> mSubgroups = new ArrayList<>();
+
+        /**
+         * Create an empty builder.
+         * @hide
+         */
+        @SystemApi
+        public Builder() {}
+
+        /**
+         * Create a builder with copies of information from original object.
+         *
+         * @param original original object
+         * @hide
+         */
+        @SystemApi
+        public Builder(@NonNull BluetoothLeBroadcastMetadata original) {
+            mSourceAddressType = original.getSourceAddressType();
+            mSourceDevice = original.getSourceDevice();
+            mSourceAdvertisingSid = original.getSourceAdvertisingSid();
+            mBroadcastId = original.getBroadcastId();
+            mPaSyncInterval = original.getPaSyncInterval();
+            mIsEncrypted = original.isEncrypted();
+            mBroadcastCode = original.getBroadcastCode();
+            mPresentationDelayMicros = original.getPresentationDelayMicros();
+            mSubgroups = original.getSubgroups();
+        }
+
+
+        /**
+         * Set the address type and MAC address of the Broadcast Source.
+         *
+         * Address type can be either {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC},
+         * {@link BluetoothDevice#ADDRESS_TYPE_RANDOM}
+         *
+         * MAC address can be Public Device Address, Random Device Address, Public Identity Address
+         * or Random (static) Identity Address
+         *
+         * @param sourceDevice source advertiser address
+         * @param sourceAddressType source advertiser address type
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setSourceDevice(@Nullable BluetoothDevice sourceDevice,
+                @BluetoothDevice.AddressType int sourceAddressType) {
+            mSourceDevice = sourceDevice;
+            mSourceAddressType = sourceAddressType;
+            return this;
+        }
+
+        /**
+         * Set Advertising_SID that is a subfield of the ADI field of the AUX_ADV_IND PDU or the
+         * LL_PERIODIC_SYNC_IND containing the SyncInfo that points to the PA transmitted by the
+         * Broadcast Source.
+         *
+         * @param sourceAdvertisingSid 1-byte long Advertising_SID of the Broadcast Source
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setSourceAdvertisingSid(int sourceAdvertisingSid) {
+            mSourceAdvertisingSid = sourceAdvertisingSid;
+            return this;
+        }
+
+        /**
+         * Set the Broadcast_ID of the Broadcast Source.
+         *
+         * @param broadcastId 3-byte long Broadcast_ID of the Broadcast Source
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setBroadcastId(int broadcastId) {
+            mBroadcastId = broadcastId;
+            return this;
+        }
+
+        /**
+         * Set Periodic Advertising Sync interval of the broadcast Source.
+         *
+         * @param paSyncInterval Periodic Advertising Sync interval of the broadcast Source,
+         *                      {@link #PA_SYNC_INTERVAL_UNKNOWN} if unknown
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setPaSyncInterval(int paSyncInterval) {
+            mPaSyncInterval = paSyncInterval;
+            return this;
+        }
+
+        /**
+         * Set whether the Broadcast Source should be encrypted.
+         *
+         * When setting up a Broadcast Source, if <var>isEncrypted</var> is true while
+         * <var>broadcastCode</var> is null, the implementation will automatically generate
+         * a Broadcast Code
+         *
+         * @param isEncrypted whether the Broadcast Source is encrypted
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setEncrypted(boolean isEncrypted) {
+            mIsEncrypted = isEncrypted;
+            return this;
+        }
+
+        /**
+         * Set the Broadcast Code currently set for this Broadcast Source.
+         *
+         * Only needed when encryption is enabled
+         *
+         * <p>As defined in Volume 3, Part C, Section 3.2.6 of Bluetooth Core Specification, Version
+         * 5.3, Broadcast Code is used to encrypt a broadcast audio stream.
+         * <p>It must be a UTF-8 string that has at least 4 octets and should not exceed 16 octets.
+         *
+         * @param broadcastCode Broadcast Code for this Broadcast Source, null if code is not
+         *                      required
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setBroadcastCode(@Nullable byte[] broadcastCode) {
+            mBroadcastCode = broadcastCode;
+            return this;
+        }
+
+        /**
+         * Set the overall presentation delay in microseconds of this Broadcast Source.
+         *
+         * Presentation delay is defined in Section 7 of the Basic Audio Profile.
+         *
+         * @param presentationDelayMicros presentation delay of this Broadcast Source in
+         *                                microseconds
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setPresentationDelayMicros(
+                @IntRange(from = 0, to = 0xFFFFFF) int presentationDelayMicros) {
+            mPresentationDelayMicros = presentationDelayMicros;
+            return this;
+        }
+
+        /**
+         * Add a subgroup to this broadcast source.
+         *
+         * @param subgroup {@link BluetoothLeBroadcastSubgroup} that contains a subgroup's metadata
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder addSubgroup(@NonNull BluetoothLeBroadcastSubgroup subgroup) {
+            mSubgroups.add(subgroup);
+            return this;
+        }
+
+        /**
+         * Clear subgroup list so that one can reset the builder after create it from an existing
+         * object.
+         *
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder clearSubgroup() {
+            mSubgroups.clear();
+            return this;
+        }
+
+        /**
+         * Build {@link BluetoothLeBroadcastMetadata}.
+         *
+         * @return {@link BluetoothLeBroadcastMetadata}
+         * @throws IllegalArgumentException if the object cannot be built
+         * @hide
+         */
+        @SystemApi
+        public @NonNull BluetoothLeBroadcastMetadata build() {
+            return new BluetoothLeBroadcastMetadata(mSourceAddressType, mSourceDevice,
+                    mSourceAdvertisingSid, mBroadcastId, mPaSyncInterval, mIsEncrypted,
+                    mBroadcastCode, mPresentationDelayMicros, mSubgroups);
+        }
+    }
+}
diff --git a/framework/java/android/bluetooth/BluetoothLeBroadcastReceiveState.java b/framework/java/android/bluetooth/BluetoothLeBroadcastReceiveState.java
new file mode 100644
index 0000000..bab17ee
--- /dev/null
+++ b/framework/java/android/bluetooth/BluetoothLeBroadcastReceiveState.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The {@link BluetoothLeBroadcastReceiveState} is used by the BASS server to expose information
+ * about a Broadcast Source.
+ *
+ * It represents the current synchronization state of the server to
+ * a PA and/or a BIG containing one or more subgroups containing one or more BISes
+ * transmitted by that Broadcast Source. The Broadcast Receive State characteristic is also
+ * used to inform clients whether the server has detected that the BIS is encrypted, whether
+ * the server requires a Broadcast_Code, and whether the server is decrypting the BIS.
+ *
+ * @hide
+ */
+@SystemApi
+public final class BluetoothLeBroadcastReceiveState implements Parcelable {
+    /**
+     * Periodic Advertising Synchronization state.
+     *
+     * <p>Periodic Advertising (PA) enables the LE Audio Broadcast Assistant to discover broadcast
+     * audio streams as well as the audio stream configuration on behalf of an LE Audio Broadcast
+     * Sink. This information can then be transferred to the LE Audio Broadcast Sink using the
+     * Periodic Advertising Synchronization Transfer (PAST) procedure.
+     *
+     * @hide
+     */
+    @IntDef(prefix = "PA_SYNC_STATE_",
+            value = {
+                    PA_SYNC_STATE_IDLE,
+                    PA_SYNC_STATE_SYNCINFO_REQUEST,
+                    PA_SYNC_STATE_SYNCHRONIZED,
+                    PA_SYNC_STATE_FAILED_TO_SYNCHRONIZE,
+                    PA_SYNC_STATE_NO_PAST
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PaSyncState {}
+
+    /**
+     * Indicates that the Broadcast Sink is not synchronized with the Periodic Advertisements (PA)
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int PA_SYNC_STATE_IDLE = 0;
+
+    /**
+     * Indicates that the Broadcast Sink requested the Broadcast Assistant to synchronize with the
+     * Periodic Advertisements (PA).
+     *
+     * <p>This is also known as scan delegation or scan offloading.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int PA_SYNC_STATE_SYNCINFO_REQUEST = 1;
+
+    /**
+     * Indicates that the Broadcast Sink is synchronized with the Periodic Advertisements (PA).
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int PA_SYNC_STATE_SYNCHRONIZED = 2;
+
+    /**
+     * Indicates that the Broadcast Sink was unable to synchronize with the Periodic Advertisements
+     * (PA).
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int PA_SYNC_STATE_FAILED_TO_SYNCHRONIZE = 3;
+
+    /**
+     * Indicates that the Broadcast Sink should be synchronized with the Periodic Advertisements
+     * (PA) using the Periodic Advertisements Synchronization Transfer (PAST) procedure.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int PA_SYNC_STATE_NO_PAST = 4;
+
+    /**
+     * Indicates that the Broadcast Sink synchronization state is invalid.
+     *
+     * @hide
+     */
+    public static final int PA_SYNC_STATE_INVALID = 0xFFFF;
+
+    /** @hide */
+    @IntDef(
+            prefix = "BIG_ENCRYPTION_STATE_",
+            value = {
+                    BIG_ENCRYPTION_STATE_NOT_ENCRYPTED,
+                    BIG_ENCRYPTION_STATE_CODE_REQUIRED,
+                    BIG_ENCRYPTION_STATE_DECRYPTING,
+                    BIG_ENCRYPTION_STATE_BAD_CODE
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface BigEncryptionState {}
+
+    /**
+     * Indicates that the Broadcast Sink is synchronized with an unencrypted audio stream from a
+     * Broadcast Source
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int BIG_ENCRYPTION_STATE_NOT_ENCRYPTED = 0;
+
+    /**
+     * Indicates that the Broadcast Sink needs a Broadcast Code to synchronize with an audio stream
+     * from a Broadcast Source, which was not provided when the audio stream from the Broadcast
+     * Source was added.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int BIG_ENCRYPTION_STATE_CODE_REQUIRED = 1;
+
+    /**
+     * Indicates that the Broadcast Sink is synchronized with an encrypted audio stream from a
+     * Broadcast Source.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int BIG_ENCRYPTION_STATE_DECRYPTING = 2;
+
+    /**
+     * Indicates that the Broadcast Sink is unable to decrypt an audio stream from a Broadcast
+     * Source due to an incorrect Broadcast Code.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int BIG_ENCRYPTION_STATE_BAD_CODE = 3;
+
+    /**
+     * Indicates that the Broadcast Sink encryption state is invalid.
+     *
+     * @hide
+     */
+    public static final int BIG_ENCRYPTION_STATE_INVALID = 0xFFFF;
+
+    private final int mSourceId;
+    private final @BluetoothDevice.AddressType int mSourceAddressType;
+    private final BluetoothDevice mSourceDevice;
+    private final int mSourceAdvertisingSid;
+    private final int mBroadcastId;
+    private final @PaSyncState int mPaSyncState;
+    private final @BigEncryptionState int mBigEncryptionState;
+    private final byte[] mBadCode;
+    private final int mNumSubgroups;
+    private final List<Long> mBisSyncState;
+    private final List<BluetoothLeAudioContentMetadata> mSubgroupMetadata;
+
+    /**
+     * Constructor to create a read-only {@link BluetoothLeBroadcastReceiveState} instance.
+     *
+     * @hide
+     */
+    public BluetoothLeBroadcastReceiveState(int sourceId, int sourceAddressType,
+            BluetoothDevice sourceDevice, int sourceAdvertisingSid, int broadcastId,
+            int paSyncState, int bigEncryptionState, byte[] badCode, int numSubgroups,
+            List<Long> bisSyncState,
+            List<BluetoothLeAudioContentMetadata> subgroupMetadata) {
+        mSourceId = sourceId;
+        mSourceAddressType = sourceAddressType;
+        mSourceDevice = sourceDevice;
+        mSourceAdvertisingSid = sourceAdvertisingSid;
+        mBroadcastId = broadcastId;
+        mPaSyncState = paSyncState;
+        mBigEncryptionState = bigEncryptionState;
+        mBadCode = badCode;
+        mNumSubgroups = numSubgroups;
+        mBisSyncState = bisSyncState;
+        mSubgroupMetadata = subgroupMetadata;
+    }
+
+    /**
+     * Get the source ID assigned by the BASS server
+     *
+     * Shall be unique for each instance of the Broadcast Receive State characteristic exposed by
+     * the server
+     *
+     * @return source ID assigned by the BASS server
+     * @hide
+     */
+    @SystemApi
+    public @IntRange(from = 0x00, to = 0xFF) int getSourceId() {
+        return mSourceId;
+    }
+
+    /**
+     * Get the address type of the Broadcast Source
+     *
+     * Can be either {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} or
+     * {@link BluetoothDevice#ADDRESS_TYPE_RANDOM
+     *
+     * @return address type of the Broadcast Source
+     * @hide
+     */
+    @SystemApi
+    public @BluetoothDevice.AddressType int getSourceAddressType() {
+        return mSourceAddressType;
+    }
+
+    /**
+     * Get the MAC address of the Broadcast Source, which can be Public Device Address,
+     * Random Device Address, Public Identity Address or Random (static) Identity Address
+     *
+     * @return MAC address of the Broadcast Source
+     * @hide
+     */
+    @SystemApi
+    public @NonNull BluetoothDevice getSourceDevice() {
+        return mSourceDevice;
+    }
+
+    /**
+     * Get Advertising_SID subfield of the ADI field of the AUX_ADV_IND PDU or the
+     * LL_PERIODIC_SYNC_IND containing the SyncInfo that points to the PA transmitted by the
+     * Broadcast Source.
+     *
+     * @return 1-byte long Advertising_SID of the Broadcast Source
+     * @hide
+     */
+    @SystemApi
+    public int getSourceAdvertisingSid() {
+        return mSourceAdvertisingSid;
+    }
+
+    /**
+     * Broadcast_ID of the Broadcast Source
+     *
+     * @return 3-byte long Broadcast_ID of the Broadcast Source
+     * @hide
+     */
+    @SystemApi
+    public int getBroadcastId() {
+        return mBroadcastId;
+    }
+
+    /**
+     * Get the Periodic Advertisement synchronization state between the Broadcast Sink and the
+     * Broadcast source
+     *
+     * Possible values are {@link #PA_SYNC_STATE_IDLE}, {@link #PA_SYNC_STATE_SYNCINFO_REQUEST},
+     * {@link #PA_SYNC_STATE_SYNCHRONIZED}, {@link #PA_SYNC_STATE_FAILED_TO_SYNCHRONIZE},
+     * {@link #PA_SYNC_STATE_NO_PAST}
+     *
+     * @return Periodic Advertisement synchronization state
+     * @hide
+     */
+    @SystemApi
+    public @PaSyncState int getPaSyncState() {
+        return mPaSyncState;
+    }
+
+    /**
+     * Get the encryption state of a Broadcast Isochronous Group (BIG)
+     *
+     * Possible values are {@link #BIG_ENCRYPTION_STATE_NOT_ENCRYPTED},
+     * {@link #BIG_ENCRYPTION_STATE_CODE_REQUIRED}, {@link #BIG_ENCRYPTION_STATE_DECRYPTING},
+     * {@link #BIG_ENCRYPTION_STATE_DECRYPTING}, and {@link #BIG_ENCRYPTION_STATE_BAD_CODE}
+     *
+     * @return encryption state of a Broadcast Isochronous Group (BIG)
+     * @hide
+     */
+    @SystemApi
+    public @BigEncryptionState int getBigEncryptionState() {
+        return mBigEncryptionState;
+    }
+
+    /**
+     * If {@link #getBigEncryptionState()} returns {@link #BIG_ENCRYPTION_STATE_BAD_CODE}, this
+     * method returns the value of the incorrect 16-octet Broadcast Code that fails to decrypt
+     * an audio stream from a Broadcast Source.
+     *
+     * @return 16-octet Broadcast Code, or null if {@link #getBigEncryptionState()} does not return
+     * {@link #BIG_ENCRYPTION_STATE_BAD_CODE}
+     * @hide
+     */
+    @SystemApi
+    public @Nullable byte[] getBadCode() {
+        return mBadCode;
+    }
+
+    /**
+     * Get number of Broadcast subgroups being added to this sink
+     *
+     * @return number of Broadcast subgroups being added to this sink
+     */
+    public int getNumSubgroups() {
+        return mNumSubgroups;
+    }
+
+    /**
+     * Get a list of bitfield on whether a Broadcast Isochronous Stream (BIS) is synchronized
+     * between the sink and source
+     *
+     * The number of items in the returned list is the same as {@link #getNumSubgroups()}. For each
+     * subgroup, at most 31 BISes are available and their synchronization state is indicated by its
+     * bit value at the particular offset (i.e. Bit 0-30 = BIS_index[1-31])
+     *
+     * For example, if (BisSyncState & 0b1 << 5) != 0, BIS 5 is synchronized between source and sync
+     *
+     * There is a special case, 0xFFFFFFFF to indicate Broadcast Sink failed to synchronize to
+     * a particular subgroup
+     *
+     * @return a list of bitfield on whether a Broadcast Isochronous Stream (BIS) is synchronized
+     * between the sink and source
+     * @hide
+     */
+    @SystemApi
+    public @NonNull List<Long> getBisSyncState() {
+        return mBisSyncState;
+    }
+
+    /**
+     * Get metadata for every subgroup added to this Broadcast Sink
+     *
+     * The number of items in the returned list is the same as {@link #getNumSubgroups()}.
+     *
+     * @return metadata for every subgroup added to this Broadcast Sink
+     * @hide
+     */
+    @SystemApi
+    public @NonNull List<BluetoothLeAudioContentMetadata> getSubgroupMetadata() {
+        return mSubgroupMetadata;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mSourceId);
+        out.writeInt(mSourceAddressType);
+        out.writeTypedObject(mSourceDevice, 0);
+        out.writeInt(mSourceAdvertisingSid);
+        out.writeInt(mBroadcastId);
+        out.writeInt(mPaSyncState);
+        out.writeInt(mBigEncryptionState);
+
+        if (mBadCode != null) {
+            out.writeInt(mBadCode.length);
+            out.writeByteArray(mBadCode);
+        } else {
+            // -1 indicates that there is no "bad broadcast code"
+            out.writeInt(-1);
+        }
+        out.writeInt(mNumSubgroups);
+        out.writeList(mBisSyncState);
+        out.writeTypedList(mSubgroupMetadata);
+    }
+
+    /**
+     * A {@link Parcelable.Creator} to create {@link BluetoothLeBroadcastReceiveState} from parcel.
+     * @hide
+     */
+    @SystemApi
+    public static final @NonNull Parcelable.Creator<BluetoothLeBroadcastReceiveState> CREATOR =
+            new Parcelable.Creator<BluetoothLeBroadcastReceiveState>() {
+                public @NonNull BluetoothLeBroadcastReceiveState createFromParcel(
+                        @NonNull Parcel in) {
+                    final int sourceId = in.readInt();
+                    final int sourceAddressType = in.readInt();
+                    final BluetoothDevice sourceDevice =
+                            in.readTypedObject(BluetoothDevice.CREATOR);
+                    final int sourceAdvertisingSid = in.readInt();
+                    final int broadcastId = in.readInt();
+                    final int paSyncState = in.readInt();
+                    final int bigEncryptionState = in.readInt();
+                    final int badCodeLen = in.readInt();
+                    byte[] badCode = null;
+
+                    if (badCodeLen != -1) {
+                        badCode = new byte[badCodeLen];
+                        if (badCodeLen > 0) {
+                            in.readByteArray(badCode);
+                        }
+                    }
+                    final byte numSubGroups = in.readByte();
+                    final List<Long> bisSyncState =
+                            in.readArrayList(Long.class.getClassLoader(), Long.class);
+                    final List<BluetoothLeAudioContentMetadata> subgroupMetadata =
+                            new ArrayList<>();
+                    in.readTypedList(subgroupMetadata, BluetoothLeAudioContentMetadata.CREATOR);
+
+                    return new BluetoothLeBroadcastReceiveState(
+                            sourceId,
+                            sourceAddressType,
+                            sourceDevice,
+                            sourceAdvertisingSid,
+                            broadcastId,
+                            paSyncState,
+                            bigEncryptionState,
+                            badCode,
+                            numSubGroups,
+                            bisSyncState,
+                            subgroupMetadata);
+                }
+
+                public @NonNull BluetoothLeBroadcastReceiveState[] newArray(int size) {
+                    return new BluetoothLeBroadcastReceiveState[size];
+                }
+            };
+}
diff --git a/framework/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java b/framework/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java
deleted file mode 100644
index cb47280..0000000
--- a/framework/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java
+++ /dev/null
@@ -1,788 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * This class represents an LE Audio Broadcast Source and the associated information that is needed
- * by Broadcast Audio Scan Service (BASS) residing on a Scan Delegator.
- *
- * <p>For example, the Scan Delegator on an LE Audio Broadcast Sink can use the information
- * contained within an instance of this class to synchronize with an LE Audio Broadcast Source in
- * order to listen to a Broadcast Audio Stream.
- *
- * <p>BroadcastAssistant has a BASS client which facilitates scanning and discovery of Broadcast
- * Sources on behalf of say a Broadcast Sink. Upon successful discovery of one or more Broadcast
- * sources, this information needs to be communicated to the BASS Server residing within the Scan
- * Delegator on a Broadcast Sink. This is achieved using the Periodic Advertising Synchronization
- * Transfer (PAST) procedure. This procedure uses information contained within an instance of this
- * class.
- *
- * @hide
- */
-public final class BluetoothLeBroadcastSourceInfo implements Parcelable {
-    private static final String TAG = "BluetoothLeBroadcastSourceInfo";
-    private static final boolean DBG = true;
-
-    /**
-     * Constants representing Broadcast Source address types
-     *
-     * @hide
-     */
-    @IntDef(
-            prefix = "LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_",
-            value = {
-                LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_PUBLIC,
-                LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_RANDOM,
-                LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID
-            })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface LeAudioBroadcastSourceAddressType {}
-
-    /**
-     * Represents a public address used by an LE Audio Broadcast Source
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_PUBLIC = 0;
-
-    /**
-     * Represents a random address used by an LE Audio Broadcast Source
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_RANDOM = 1;
-
-    /**
-     * Represents an invalid address used by an LE Audio Broadcast Seurce
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID = 0xFFFF;
-
-    /**
-     * Periodic Advertising Synchronization state
-     *
-     * <p>Periodic Advertising (PA) enables the LE Audio Broadcast Assistant to discover broadcast
-     * audio streams as well as the audio stream configuration on behalf of an LE Audio Broadcast
-     * Sink. This information can then be transferred to the LE Audio Broadcast Sink using the
-     * Periodic Advertising Synchronizaton Transfer (PAST) procedure.
-     *
-     * @hide
-     */
-    @IntDef(
-            prefix = "LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_",
-            value = {
-                LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IDLE,
-                LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNCINFO_REQ,
-                LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IN_SYNC,
-                LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNC_FAIL,
-                LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_NO_PAST
-            })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface LeAudioBroadcastSinkPaSyncState {}
-
-    /**
-     * Indicates that the Broadcast Sink is not synchronized with the Periodic Advertisements (PA)
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IDLE = 0;
-
-    /**
-     * Indicates that the Broadcast Sink requested the Broadcast Assistant to synchronize with the
-     * Periodic Advertisements (PA).
-     *
-     * <p>This is also known as scan delegation or scan offloading.
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNCINFO_REQ = 1;
-
-    /**
-     * Indicates that the Broadcast Sink is synchronized with the Periodic Advertisements (PA).
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IN_SYNC = 2;
-
-    /**
-     * Indicates that the Broadcast Sink was unable to synchronize with the Periodic Advertisements
-     * (PA).
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNC_FAIL = 3;
-
-    /**
-     * Indicates that the Broadcast Sink should be synchronized with the Periodic Advertisements
-     * (PA) using the Periodic Advertisements Synchronization Transfert (PAST) procedure.
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_NO_PAST = 4;
-
-    /**
-     * Indicates that the Broadcast Sink synchornization state is invalid.
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID = 0xFFFF;
-
-    /** @hide */
-    @IntDef(
-            prefix = "LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_",
-            value = {
-                LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_NOT_SYNCHRONIZED,
-                LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_SYNCHRONIZED
-            })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface LeAudioBroadcastSinkAudioSyncState {}
-
-    /**
-     * Indicates that the Broadcast Sink is not synchronized with a Broadcast Audio Stream.
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_NOT_SYNCHRONIZED = 0;
-
-    /**
-     * Indicates that the Broadcast Sink is synchronized with a Broadcast Audio Stream.
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_SYNCHRONIZED = 1;
-
-    /**
-     * Indicates that the Broadcast Sink audio synchronization state is invalid.
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID = 0xFFFF;
-
-    /** @hide */
-    @IntDef(
-            prefix = "LE_AUDIO_BROADCAST_SINK_ENC_STATE_",
-            value = {
-                LE_AUDIO_BROADCAST_SINK_ENC_STATE_NOT_ENCRYPTED,
-                LE_AUDIO_BROADCAST_SINK_ENC_STATE_CODE_REQUIRED,
-                LE_AUDIO_BROADCAST_SINK_ENC_STATE_DECRYPTING,
-                LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE
-            })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface LeAudioBroadcastSinkEncryptionState {}
-
-    /**
-     * Indicates that the Broadcast Sink is synchronized with an unencrypted audio stream.
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_NOT_ENCRYPTED = 0;
-
-    /**
-     * Indicates that the Broadcast Sink needs a Broadcast Code to synchronize with the audio
-     * stream.
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_CODE_REQUIRED = 1;
-
-    /**
-     * Indicates that the Broadcast Sink is synchronized with an encrypted audio stream.
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_DECRYPTING = 2;
-
-    /**
-     * Indicates that the Broadcast Sink is unable to decrypt an audio stream due to an incorrect
-     * Broadcast Code
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE = 3;
-
-    /**
-     * Indicates that the Broadcast Sink encryption state is invalid.
-     *
-     * @hide
-     */
-    public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID = 0xFF;
-
-    /**
-     * Represents an invalid LE Audio Broadcast Source ID
-     *
-     * @hide
-     */
-    public static final byte LE_AUDIO_BROADCAST_SINK_INVALID_SOURCE_ID = (byte) 0x00;
-
-    /**
-     * Represents an invalid Broadcast ID of a Broadcast Source
-     *
-     * @hide
-     */
-    public static final int INVALID_BROADCAST_ID = 0xFFFFFF;
-
-    private byte mSourceId;
-    private @LeAudioBroadcastSourceAddressType int mSourceAddressType;
-    private BluetoothDevice mSourceDevice;
-    private byte mSourceAdvSid;
-    private int mBroadcastId;
-    private @LeAudioBroadcastSinkPaSyncState int mPaSyncState;
-    private @LeAudioBroadcastSinkEncryptionState int mEncryptionStatus;
-    private @LeAudioBroadcastSinkAudioSyncState int mAudioSyncState;
-    private byte[] mBadBroadcastCode;
-    private byte mNumSubGroups;
-    private Map<Integer, Integer> mSubgroupBisSyncState = new HashMap<Integer, Integer>();
-    private Map<Integer, byte[]> mSubgroupMetadata = new HashMap<Integer, byte[]>();
-
-    private String mBroadcastCode;
-    private static final int BIS_NO_PREF = 0xFFFFFFFF;
-    private static final int BROADCAST_CODE_SIZE = 16;
-
-    /**
-     * Constructor to create an Empty object of {@link BluetoothLeBroadcastSourceInfo } with the
-     * given Source Id.
-     *
-     * <p>This is mainly used to represent the Empty Broadcast Source entries
-     *
-     * @param sourceId Source Id for this Broadcast Source info object
-     * @hide
-     */
-    public BluetoothLeBroadcastSourceInfo(byte sourceId) {
-        mSourceId = sourceId;
-        mSourceAddressType = LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID;
-        mSourceDevice = null;
-        mSourceAdvSid = (byte) 0x00;
-        mBroadcastId = INVALID_BROADCAST_ID;
-        mPaSyncState = LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID;
-        mAudioSyncState = LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID;
-        mEncryptionStatus = LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID;
-        mBadBroadcastCode = null;
-        mNumSubGroups = 0;
-        mBroadcastCode = null;
-    }
-
-    /*package*/ BluetoothLeBroadcastSourceInfo(
-            byte sourceId,
-            @LeAudioBroadcastSourceAddressType int addressType,
-            @NonNull BluetoothDevice device,
-            byte advSid,
-            int broadcastId,
-            @LeAudioBroadcastSinkPaSyncState int paSyncstate,
-            @LeAudioBroadcastSinkEncryptionState int encryptionStatus,
-            @LeAudioBroadcastSinkAudioSyncState int audioSyncstate,
-            @Nullable byte[] badCode,
-            byte numSubGroups,
-            @NonNull Map<Integer, Integer> bisSyncState,
-            @Nullable Map<Integer, byte[]> subgroupMetadata,
-            @NonNull String broadcastCode) {
-        mSourceId = sourceId;
-        mSourceAddressType = addressType;
-        mSourceDevice = device;
-        mSourceAdvSid = advSid;
-        mBroadcastId = broadcastId;
-        mPaSyncState = paSyncstate;
-        mEncryptionStatus = encryptionStatus;
-        mAudioSyncState = audioSyncstate;
-
-        if (badCode != null && badCode.length != 0) {
-            mBadBroadcastCode = new byte[badCode.length];
-            System.arraycopy(badCode, 0, mBadBroadcastCode, 0, badCode.length);
-        }
-        mNumSubGroups = numSubGroups;
-        mSubgroupBisSyncState = new HashMap<Integer, Integer>(bisSyncState);
-        mSubgroupMetadata = new HashMap<Integer, byte[]>(subgroupMetadata);
-        mBroadcastCode = broadcastCode;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof BluetoothLeBroadcastSourceInfo) {
-            BluetoothLeBroadcastSourceInfo other = (BluetoothLeBroadcastSourceInfo) o;
-            return (other.mSourceId == mSourceId
-                    && other.mSourceAddressType == mSourceAddressType
-                    && other.mSourceDevice == mSourceDevice
-                    && other.mSourceAdvSid == mSourceAdvSid
-                    && other.mBroadcastId == mBroadcastId
-                    && other.mPaSyncState == mPaSyncState
-                    && other.mEncryptionStatus == mEncryptionStatus
-                    && other.mAudioSyncState == mAudioSyncState
-                    && Arrays.equals(other.mBadBroadcastCode, mBadBroadcastCode)
-                    && other.mNumSubGroups == mNumSubGroups
-                    && mSubgroupBisSyncState.equals(other.mSubgroupBisSyncState)
-                    && mSubgroupMetadata.equals(other.mSubgroupMetadata)
-                    && other.mBroadcastCode == mBroadcastCode);
-        }
-        return false;
-    }
-
-    /**
-     * Checks if an instance of {@link BluetoothLeBroadcastSourceInfo} is empty.
-     *
-     * @hide
-     */
-    public boolean isEmpty() {
-        boolean ret = false;
-        if (mSourceAddressType == LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID
-                && mSourceDevice == null
-                && mSourceAdvSid == (byte) 0
-                && mPaSyncState == LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID
-                && mEncryptionStatus == LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID
-                && mAudioSyncState == LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID
-                && mBadBroadcastCode == null
-                && mNumSubGroups == 0
-                && mSubgroupBisSyncState.size() == 0
-                && mSubgroupMetadata.size() == 0
-                && mBroadcastCode == null) {
-            ret = true;
-        }
-        return ret;
-    }
-
-    /**
-     * Compares an instance of {@link BluetoothLeBroadcastSourceInfo} with the provided instance.
-     *
-     * @hide
-     */
-    public boolean matches(BluetoothLeBroadcastSourceInfo srcInfo) {
-        boolean ret = false;
-        if (srcInfo == null) {
-            ret = false;
-        } else {
-            if (mSourceDevice == null) {
-                if (mSourceAdvSid == srcInfo.getAdvertisingSid()
-                        && mSourceAddressType == srcInfo.getAdvAddressType()) {
-                    ret = true;
-                }
-            } else {
-                if (mSourceDevice.equals(srcInfo.getSourceDevice())
-                        && mSourceAdvSid == srcInfo.getAdvertisingSid()
-                        && mSourceAddressType == srcInfo.getAdvAddressType()
-                        && mBroadcastId == srcInfo.getBroadcastId()) {
-                    ret = true;
-                }
-            }
-        }
-        return ret;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(
-                mSourceId,
-                mSourceAddressType,
-                mSourceDevice,
-                mSourceAdvSid,
-                mBroadcastId,
-                mPaSyncState,
-                mEncryptionStatus,
-                mAudioSyncState,
-                mBadBroadcastCode,
-                mNumSubGroups,
-                mSubgroupBisSyncState,
-                mSubgroupMetadata,
-                mBroadcastCode);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public String toString() {
-        return "{BluetoothLeBroadcastSourceInfo : mSourceId"
-                + mSourceId
-                + " addressType: "
-                + mSourceAddressType
-                + " sourceDevice: "
-                + mSourceDevice
-                + " mSourceAdvSid:"
-                + mSourceAdvSid
-                + " mBroadcastId:"
-                + mBroadcastId
-                + " mPaSyncState:"
-                + mPaSyncState
-                + " mEncryptionStatus:"
-                + mEncryptionStatus
-                + " mAudioSyncState:"
-                + mAudioSyncState
-                + " mBadBroadcastCode:"
-                + mBadBroadcastCode
-                + " mNumSubGroups:"
-                + mNumSubGroups
-                + " mSubgroupBisSyncState:"
-                + mSubgroupBisSyncState
-                + " mSubgroupMetadata:"
-                + mSubgroupMetadata
-                + " mBroadcastCode:"
-                + mBroadcastCode
-                + "}";
-    }
-
-    /**
-     * Get the Source Id
-     *
-     * @return byte representing the Source Id, {@link
-     *     #LE_AUDIO_BROADCAST_ASSISTANT_INVALID_SOURCE_ID} if invalid
-     * @hide
-     */
-    public byte getSourceId() {
-        return mSourceId;
-    }
-
-    /**
-     * Set the Source Id
-     *
-     * @param sourceId source Id
-     * @hide
-     */
-    public void setSourceId(byte sourceId) {
-        mSourceId = sourceId;
-    }
-
-    /**
-     * Set the Broadcast Source device
-     *
-     * @param sourceDevice the Broadcast Source BluetoothDevice
-     * @hide
-     */
-    public void setSourceDevice(@NonNull BluetoothDevice sourceDevice) {
-        mSourceDevice = sourceDevice;
-    }
-
-    /**
-     * Get the Broadcast Source BluetoothDevice
-     *
-     * @return Broadcast Source BluetoothDevice
-     * @hide
-     */
-    public @NonNull BluetoothDevice getSourceDevice() {
-        return mSourceDevice;
-    }
-
-    /**
-     * Set the address type of the Broadcast Source advertisements
-     *
-     * @hide
-     */
-    public void setAdvAddressType(@LeAudioBroadcastSourceAddressType int addressType) {
-        mSourceAddressType = addressType;
-    }
-
-    /**
-     * Get the address type used by advertisements from the Broadcast Source.
-     * BluetoothLeBroadcastSourceInfo Object
-     *
-     * @hide
-     */
-    @LeAudioBroadcastSourceAddressType
-    public int getAdvAddressType() {
-        return mSourceAddressType;
-    }
-
-    /**
-     * Set the advertising SID of the Broadcast Source advertisement.
-     *
-     * @param advSid advertising SID of the Broadcast Source
-     * @hide
-     */
-    public void setAdvertisingSid(byte advSid) {
-        mSourceAdvSid = advSid;
-    }
-
-    /**
-     * Get the advertising SID of the Broadcast Source advertisement.
-     *
-     * @return advertising SID of the Broadcast Source
-     * @hide
-     */
-    public byte getAdvertisingSid() {
-        return mSourceAdvSid;
-    }
-
-    /**
-     * Get the Broadcast ID of the Broadcast Source.
-     *
-     * @return broadcast ID
-     * @hide
-     */
-    public int getBroadcastId() {
-        return mBroadcastId;
-    }
-
-    /**
-     * Set the Periodic Advertising (PA) Sync State.
-     *
-     * @hide
-     */
-    /*package*/ void setPaSyncState(@LeAudioBroadcastSinkPaSyncState int paSyncState) {
-        mPaSyncState = paSyncState;
-    }
-
-    /**
-     * Get the Periodic Advertising (PA) Sync State
-     *
-     * @hide
-     */
-    public @LeAudioBroadcastSinkPaSyncState int getMetadataSyncState() {
-        return mPaSyncState;
-    }
-
-    /**
-     * Set the audio sync state
-     *
-     * @hide
-     */
-    /*package*/ void setAudioSyncState(@LeAudioBroadcastSinkAudioSyncState int audioSyncState) {
-        mAudioSyncState = audioSyncState;
-    }
-
-    /**
-     * Get the audio sync state
-     *
-     * @hide
-     */
-    public @LeAudioBroadcastSinkAudioSyncState int getAudioSyncState() {
-        return mAudioSyncState;
-    }
-
-    /**
-     * Set the encryption status
-     *
-     * @hide
-     */
-    /*package*/ void setEncryptionStatus(
-            @LeAudioBroadcastSinkEncryptionState int encryptionStatus) {
-        mEncryptionStatus = encryptionStatus;
-    }
-
-    /**
-     * Get the encryption status
-     *
-     * @hide
-     */
-    public @LeAudioBroadcastSinkEncryptionState int getEncryptionStatus() {
-        return mEncryptionStatus;
-    }
-
-    /**
-     * Get the incorrect broadcast code that the Scan delegator used to decrypt the Broadcast Audio
-     * Stream and failed.
-     *
-     * <p>This code is valid only if {@link #getEncryptionStatus} returns {@link
-     * #LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE}
-     *
-     * @return byte array containing bad broadcast value, null if the current encryption status is
-     *     not {@link #LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE}
-     * @hide
-     */
-    public @Nullable byte[] getBadBroadcastCode() {
-        return mBadBroadcastCode;
-    }
-
-    /**
-     * Get the number of subgroups.
-     *
-     * @return number of subgroups
-     * @hide
-     */
-    public byte getNumberOfSubGroups() {
-        return mNumSubGroups;
-    }
-
-    public @NonNull Map<Integer, Integer> getSubgroupBisSyncState() {
-        return mSubgroupBisSyncState;
-    }
-
-    public void setSubgroupBisSyncState(@NonNull Map<Integer, Integer> bisSyncState) {
-        mSubgroupBisSyncState = new HashMap<Integer, Integer>(bisSyncState);
-    }
-
-    /*package*/ void setBroadcastCode(@NonNull String broadcastCode) {
-        mBroadcastCode = broadcastCode;
-    }
-
-    /**
-     * Get the broadcast code
-     *
-     * @return
-     * @hide
-     */
-    public @NonNull String getBroadcastCode() {
-        return mBroadcastCode;
-    }
-
-    /**
-     * Set the broadcast ID
-     *
-     * @param broadcastId broadcast ID of the Broadcast Source
-     * @hide
-     */
-    public void setBroadcastId(int broadcastId) {
-        mBroadcastId = broadcastId;
-    }
-
-    private void writeSubgroupBisSyncStateToParcel(
-            @NonNull Parcel dest, @NonNull Map<Integer, Integer> subgroupBisSyncState) {
-        dest.writeInt(subgroupBisSyncState.size());
-        for (Map.Entry<Integer, Integer> entry : subgroupBisSyncState.entrySet()) {
-            dest.writeInt(entry.getKey());
-            dest.writeInt(entry.getValue());
-        }
-    }
-
-    private static void readSubgroupBisSyncStateFromParcel(
-            @NonNull Parcel in, @NonNull Map<Integer, Integer> subgroupBisSyncState) {
-        int size = in.readInt();
-
-        for (int i = 0; i < size; i++) {
-            Integer key = in.readInt();
-            Integer value = in.readInt();
-            subgroupBisSyncState.put(key, value);
-        }
-    }
-
-    private void writeSubgroupMetadataToParcel(
-            @NonNull Parcel dest, @Nullable Map<Integer, byte[]> subgroupMetadata) {
-        if (subgroupMetadata == null) {
-            dest.writeInt(0);
-            return;
-        }
-
-        dest.writeInt(subgroupMetadata.size());
-        for (Map.Entry<Integer, byte[]> entry : subgroupMetadata.entrySet()) {
-            dest.writeInt(entry.getKey());
-            byte[] metadata = entry.getValue();
-            if (metadata != null) {
-                dest.writeInt(metadata.length);
-                dest.writeByteArray(metadata);
-            }
-        }
-    }
-
-    private static void readSubgroupMetadataFromParcel(
-            @NonNull Parcel in, @NonNull Map<Integer, byte[]> subgroupMetadata) {
-        int size = in.readInt();
-
-        for (int i = 0; i < size; i++) {
-            Integer key = in.readInt();
-            Integer metaDataLen = in.readInt();
-            byte[] metadata = null;
-            if (metaDataLen != 0) {
-                metadata = new byte[metaDataLen];
-                in.readByteArray(metadata);
-            }
-            subgroupMetadata.put(key, metadata);
-        }
-    }
-
-    public static final @NonNull Parcelable.Creator<BluetoothLeBroadcastSourceInfo> CREATOR =
-            new Parcelable.Creator<BluetoothLeBroadcastSourceInfo>() {
-                public @NonNull BluetoothLeBroadcastSourceInfo createFromParcel(
-                        @NonNull Parcel in) {
-                    final byte sourceId = in.readByte();
-                    final int sourceAddressType = in.readInt();
-                    final BluetoothDevice sourceDevice =
-                            in.readTypedObject(BluetoothDevice.CREATOR);
-                    final byte sourceAdvSid = in.readByte();
-                    final int broadcastId = in.readInt();
-                    final int paSyncState = in.readInt();
-                    final int audioSyncState = in.readInt();
-                    final int encryptionStatus = in.readInt();
-                    final int badBroadcastLen = in.readInt();
-                    byte[] badBroadcastCode = null;
-
-                    if (badBroadcastLen > 0) {
-                        badBroadcastCode = new byte[badBroadcastLen];
-                        in.readByteArray(badBroadcastCode);
-                    }
-                    final byte numSubGroups = in.readByte();
-                    final String broadcastCode = in.readString();
-                    Map<Integer, Integer> subgroupBisSyncState = new HashMap<Integer, Integer>();
-                    readSubgroupBisSyncStateFromParcel(in, subgroupBisSyncState);
-                    Map<Integer, byte[]> subgroupMetadata = new HashMap<Integer, byte[]>();
-                    readSubgroupMetadataFromParcel(in, subgroupMetadata);
-
-                    BluetoothLeBroadcastSourceInfo srcInfo =
-                            new BluetoothLeBroadcastSourceInfo(
-                                    sourceId,
-                                    sourceAddressType,
-                                    sourceDevice,
-                                    sourceAdvSid,
-                                    broadcastId,
-                                    paSyncState,
-                                    encryptionStatus,
-                                    audioSyncState,
-                                    badBroadcastCode,
-                                    numSubGroups,
-                                    subgroupBisSyncState,
-                                    subgroupMetadata,
-                                    broadcastCode);
-                    return srcInfo;
-                }
-
-                public @NonNull BluetoothLeBroadcastSourceInfo[] newArray(int size) {
-                    return new BluetoothLeBroadcastSourceInfo[size];
-                }
-            };
-
-    @Override
-    public void writeToParcel(@NonNull Parcel out, int flags) {
-        out.writeByte(mSourceId);
-        out.writeInt(mSourceAddressType);
-        out.writeTypedObject(mSourceDevice, 0);
-        out.writeByte(mSourceAdvSid);
-        out.writeInt(mBroadcastId);
-        out.writeInt(mPaSyncState);
-        out.writeInt(mAudioSyncState);
-        out.writeInt(mEncryptionStatus);
-
-        if (mBadBroadcastCode != null) {
-            out.writeInt(mBadBroadcastCode.length);
-            out.writeByteArray(mBadBroadcastCode);
-        } else {
-            // zero indicates that there is no "bad broadcast code"
-            out.writeInt(0);
-        }
-        out.writeByte(mNumSubGroups);
-        out.writeString(mBroadcastCode);
-        writeSubgroupBisSyncStateToParcel(out, mSubgroupBisSyncState);
-        writeSubgroupMetadataToParcel(out, mSubgroupMetadata);
-    }
-
-    private static void log(@NonNull String msg) {
-        if (DBG) {
-            Log.d(TAG, msg);
-        }
-    }
-}
-;
diff --git a/framework/java/android/bluetooth/BluetoothLeBroadcastSubgroup.java b/framework/java/android/bluetooth/BluetoothLeBroadcastSubgroup.java
new file mode 100644
index 0000000..273ac43
--- /dev/null
+++ b/framework/java/android/bluetooth/BluetoothLeBroadcastSubgroup.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class contains the subgroup level information as defined in the BASE structure of Basic
+ * Audio profile.
+ *
+ * @hide
+ */
+@SystemApi
+public final class BluetoothLeBroadcastSubgroup implements Parcelable {
+    private final long mCodecId;
+    private final BluetoothLeAudioCodecConfigMetadata mCodecSpecificConfig;
+    private final BluetoothLeAudioContentMetadata mContentMetadata;
+    private final boolean mNoChannelPreference;
+    private final List<BluetoothLeBroadcastChannel> mChannels;
+
+    private BluetoothLeBroadcastSubgroup(long codecId,
+            BluetoothLeAudioCodecConfigMetadata codecSpecificConfig,
+            BluetoothLeAudioContentMetadata contentMetadata, boolean noChannelPreference,
+            List<BluetoothLeBroadcastChannel> channels) {
+        mCodecId = codecId;
+        mCodecSpecificConfig = codecSpecificConfig;
+        mContentMetadata = contentMetadata;
+        mNoChannelPreference = noChannelPreference;
+        mChannels = channels;
+    }
+
+    /**
+     * Get the codec ID field as defined by the Basic Audio Profile.
+     *
+     * The codec ID field has 5 octets, with
+     * - Octet 0: Coding_Format as defined in Bluetooth Assigned Numbers
+     * - Octet 1-2: Company ID as defined in Bluetooth Assigned Numbers
+     *              Shall be 0x0000 if octet 0 != 0xFF
+     * - Octet 3-4: Vendor-specific codec ID
+     *              Shall be 0x0000 if octet 0 != 0xFF
+     *
+     * @return 5-byte codec ID field in Java long format
+     * @hide
+     */
+    @SystemApi
+    public long getCodecId() {
+        return mCodecId;
+    }
+
+    /**
+     * Get codec specific config metadata for this subgroup.
+     *
+     * @return codec specific config metadata for this subgroup
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    public BluetoothLeAudioCodecConfigMetadata getCodecSpecificConfig() {
+        return mCodecSpecificConfig;
+    }
+
+    /**
+     * Get content metadata for this Broadcast Source subgroup.
+     *
+     * @return content metadata for this Broadcast Source subgroup
+     * @hide
+     */
+    @SystemApi
+    public @NonNull BluetoothLeAudioContentMetadata getContentMetadata() {
+        return mContentMetadata;
+    }
+
+    /**
+     * Indicate if Broadcast Sink should have no Broadcast Channel (BIS) preference.
+     *
+     * Only used by Broadcast Assistant and Sink. Ignored by Broadcast Source
+     *
+     * @return true if Broadcast Sink should have no Broadcast Channel (BIS) preference
+     * @hide
+     */
+    @SystemApi
+    public boolean isNoChannelPreference() {
+        return mNoChannelPreference;
+    }
+
+    /**
+     * Get list of Broadcast Channels included in this Broadcast subgroup.
+     *
+     * Each Broadcast Channel represents a Broadcast Isochronous Stream (BIS)
+     *
+     * A Broadcast subgroup should contain at least 1 Broadcast Channel
+     *
+     * @return list of Broadcast Channels included in this Broadcast subgroup
+     * @hide
+     */
+    @SystemApi
+    public @NonNull List<BluetoothLeBroadcastChannel> getChannels() {
+        return mChannels;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(mCodecId);
+        out.writeTypedObject(mCodecSpecificConfig, 0);
+        out.writeTypedObject(mContentMetadata, 0);
+        out.writeBoolean(mNoChannelPreference);
+        out.writeTypedList(mChannels);
+    }
+
+    /**
+     * A {@link Parcelable.Creator} to create {@link BluetoothLeBroadcastSubgroup} from parcel.
+     * @hide
+     */
+    @SystemApi
+    public static final @NonNull Parcelable.Creator<BluetoothLeBroadcastSubgroup> CREATOR =
+            new Parcelable.Creator<BluetoothLeBroadcastSubgroup>() {
+                public @NonNull BluetoothLeBroadcastSubgroup createFromParcel(@NonNull Parcel in) {
+                    Builder builder = new Builder();
+                    builder.setCodecId(in.readLong());
+                    builder.setCodecSpecificConfig(in.readTypedObject(
+                            BluetoothLeAudioCodecConfigMetadata.CREATOR));
+                    builder.setNoChannelPreference(in.readBoolean());
+                    List<BluetoothLeBroadcastChannel> channels = new ArrayList<>();
+                    in.readTypedList(channels, BluetoothLeBroadcastChannel.CREATOR);
+                    for (BluetoothLeBroadcastChannel channel : channels) {
+                        builder.addChannel(channel);
+                    }
+                    return builder.build();
+                }
+
+                public @NonNull BluetoothLeBroadcastSubgroup[] newArray(int size) {
+                    return new BluetoothLeBroadcastSubgroup[size];
+                }
+    };
+
+    private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
+
+    /**
+     * Builder for {@link BluetoothLeBroadcastSubgroup}.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+        private long mCodecId = UNKNOWN_VALUE_PLACEHOLDER;
+        private BluetoothLeAudioCodecConfigMetadata mCodecSpecificConfig = null;
+        private BluetoothLeAudioContentMetadata mContentMetadata = null;
+        private boolean mNoChannelPreference = false;
+        private List<BluetoothLeBroadcastChannel> mChannels = new ArrayList<>();
+
+        /**
+         * Create an empty constructor.
+         * @hide
+         */
+        @SystemApi
+        public Builder() {}
+
+        /**
+         * Create a builder with copies of information from original object.
+         *
+         * @param original original object
+         * @hide
+         */
+        @SystemApi
+        public Builder(@NonNull BluetoothLeBroadcastSubgroup original) {
+            mCodecId = original.getCodecId();
+            mCodecSpecificConfig = original.getCodecSpecificConfig();
+            mContentMetadata = original.getContentMetadata();
+            mNoChannelPreference = original.isNoChannelPreference();
+            mChannels = original.getChannels();
+        }
+
+
+        /**
+         * Set the codec ID field as defined by the Basic Audio Profile.
+         *
+         * The codec ID field has 5 octets, with
+         * - Octet 0: Coding_Format as defined in Bluetooth Assigned Numbers
+         * - Octet 1-2: Company ID as defined in Bluetooth Assigned Numbers
+         *              Shall be 0x0000 if octet 0 != 0xFF
+         * - Octet 3-4: Vendor-specific codec ID
+         *              Shall be 0x0000 if octet 0 != 0xFF
+         *
+         * @param codecId 5-byte codec ID field in Java long format
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setCodecId(long codecId) {
+            mCodecId = codecId;
+            return this;
+        }
+
+        /**
+         * Set codec specific config metadata for this subgroup.
+         *
+         * @param codecSpecificConfig codec specific config metadata for this subgroup
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setCodecSpecificConfig(
+                @NonNull BluetoothLeAudioCodecConfigMetadata codecSpecificConfig) {
+            mCodecSpecificConfig = codecSpecificConfig;
+            return this;
+        }
+
+        /**
+         * Set content metadata for this Broadcast Source subgroup.
+         *
+         * @param contentMetadata content metadata for this Broadcast Source subgroup
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setContentMetadata(
+                @NonNull BluetoothLeAudioContentMetadata contentMetadata) {
+            mContentMetadata = contentMetadata;
+            return this;
+        }
+
+        /**
+         * Set if Broadcast Sink should have no Broadcast Channel (BIS) preference.
+         *
+         * Only used by Broadcast Assistant and Sink. Ignored by Broadcast Source
+         *
+         * @param isNoChannelPreference true if Broadcast Sink should have no Broadcast Channel
+         *                              (BIS) preference
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setNoChannelPreference(boolean isNoChannelPreference) {
+            mNoChannelPreference = isNoChannelPreference;
+            return this;
+        }
+
+        /**
+         * Add a Broadcast Channel to this Broadcast subgroup.
+         *
+         * Each Broadcast Channel represents a Broadcast Isochronous Stream (BIS)
+         *
+         * A Broadcast subgroup should contain at least 1 Broadcast Channel
+         *
+         * @param channel  a Broadcast Channel to be added to this Broadcast subgroup
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder addChannel(@NonNull BluetoothLeBroadcastChannel channel) {
+            mChannels.add(channel);
+            return this;
+        }
+
+        /**
+         * Clear channel list so that one can reset the builder after create it from an existing
+         * object.
+         *
+         * @return this builder
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder clearChannel() {
+            mChannels.clear();
+            return this;
+        }
+
+        /**
+         * Build {@link BluetoothLeBroadcastSubgroup}.
+         *
+         * @return constructed {@link BluetoothLeBroadcastSubgroup}
+         * @throws IllegalArgumentException if the object cannot be built
+         * @hide
+         */
+        @SystemApi
+        public @NonNull BluetoothLeBroadcastSubgroup build() {
+            return new BluetoothLeBroadcastSubgroup(mCodecId, mCodecSpecificConfig,
+                    mContentMetadata, mNoChannelPreference, mChannels);
+        }
+    }
+}
diff --git a/framework/java/android/bluetooth/BluetoothProfile.java b/framework/java/android/bluetooth/BluetoothProfile.java
index 1fa2bcf..c29a671 100644
--- a/framework/java/android/bluetooth/BluetoothProfile.java
+++ b/framework/java/android/bluetooth/BluetoothProfile.java
@@ -237,6 +237,7 @@
      *
      * @hide
      */
+    @SystemApi
     int LE_AUDIO_BROADCAST = 26;
 
     /**
@@ -253,12 +254,20 @@
     int HAP_CLIENT = 28;
 
     /**
+     * LE Audio Broadcast Assistant
+     *
+     * @hide
+     */
+    @SystemApi
+    int LE_AUDIO_BROADCAST_ASSISTANT = 29;
+
+    /**
      * Max profile ID. This value should be updated whenever a new profile is added to match
      * the largest value assigned to a profile.
      *
      * @hide
      */
-    int MAX_PROFILE_ID = 28;
+    int MAX_PROFILE_ID = 29;
 
     /**
      * Default priority for devices that we try to auto-connect to and
diff --git a/framework/java/android/bluetooth/BluetoothStatusCodes.java b/framework/java/android/bluetooth/BluetoothStatusCodes.java
index 5017198..01e30db 100644
--- a/framework/java/android/bluetooth/BluetoothStatusCodes.java
+++ b/framework/java/android/bluetooth/BluetoothStatusCodes.java
@@ -133,6 +133,94 @@
     public static final int ERROR_TIMEOUT = 15;
 
     /**
+     * Indicates that some local application caused the event.
+     * @hide
+     */
+    @SystemApi
+    public static final int REASON_LOCAL_APP_REQUEST = 16;
+
+    /**
+     * Indicate that this change was initiated by the Bluetooth implementation on this device
+     * @hide
+     */
+    @SystemApi
+    public static final int REASON_LOCAL_STACK_REQUEST = 17;
+
+    /**
+     * Indicate that this change was initiated by the remote device.
+     * @hide
+     */
+    @SystemApi
+    public static final int REASON_REMOTE_REQUEST = 18;
+
+    /**
+     * Indicates that the local system policy caused the change, such as privacy policy, power
+     * management policy, permission changes, and more.
+     * @hide
+     */
+    @SystemApi
+    public static final int REASON_SYSTEM_POLICY = 19;
+
+    /**
+     * Indicates that an underlying hardware incurred some error maybe try again later or toggle
+     * the hardware state.
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_HARDWARE_GENERIC = 20;
+
+    /**
+     * Indicates that the operation failed due to bad API input parameter that is not covered
+     * by other more detailed error code
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_BAD_PARAMETERS = 21;
+
+    /**
+     * Indicate that there is not enough local resource to perform the requested operation
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_LOCAL_NOT_ENOUGH_RESOURCES = 22;
+
+    /**
+     * Indicate that a remote device does not have enough resource to perform the requested
+     * operation
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_REMOTE_NOT_ENOUGH_RESOURCES = 23;
+
+    /**
+     * Indicates that the remote rejected this operation for reasons not covered above
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_REMOTE_OPERATION_REJECTED = 24;
+
+    /**
+     * Indicates that there is an underlying link error between the local and remote devices.
+     *
+     * Maybe try again later or disconnect and retry.
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_REMOTE_LINK_ERROR = 25;
+
+    /**
+     * A generic error code to indicate that the system is already in a target state that an API
+     * tries to request.
+     *
+     * For example, this error code will be delivered if someone tries to stop scanning when
+     * scan has already stopped, or start scanning when scan has already started.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_ALREADY_IN_TARGET_STATE = 26;
+
+    /**
      * A GATT writeCharacteristic request is not permitted on the remote device.
      */
     public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200;
@@ -279,66 +367,6 @@
     public static final int ERROR_DISCONNECT_REASON_BAD_PARAMETERS = 1109;
 
     /**
-     * Indicates that setting the LE Audio Broadcast mode failed.
-     * <p>
-     * Example solution: Change parameters and try again. If error persists, the app can report
-     * telemetry and/or log the error in a bugreport.
-     *
-     * @hide
-     */
-    public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED = 1110;
-
-    /**
-     * Indicates that setting a new encryption key for Bluetooth LE Audio Broadcast Source failed.
-     * <p>
-     * Example solution: Change parameters and try again. If error persists, the app can report
-     * telemetry and/or log the error in a bugreport.
-     *
-     * @hide
-     */
-    public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_ENCRYPTION_KEY_FAILED = 1111;
-
-    /**
-     * Indicates that connecting to a remote Broadcast Audio Scan Service failed.
-     * <p>
-     * Example solution: Change parameters and try again. If error persists, the app can report
-     * telemetry and/or log the error in a bugreport.
-     *
-     * @hide
-     */
-    public static final int ERROR_LE_AUDIO_BROADCAST_AUDIO_SCAN_SERVICE_CONNECT_FAILED = 1112;
-
-    /**
-     * Indicates that disconnecting from a remote Broadcast Audio Scan Service failed.
-     * <p>
-     * Example solution: Change parameters and try again. If error persists, the app can report
-     * telemetry and/or log the error in a bugreport.
-     *
-     * @hide
-     */
-    public static final int ERROR_LE_AUDIO_BROADCAST_AUDIO_SCAN_SERVICE_DISCONNECT_FAILED = 1113;
-
-    /**
-     * Indicates that enabling LE Audio Broadcast encryption failed
-     * <p>
-     * Example solution: Change parameters and try again. If error persists, the app can report
-     * telemetry and/or log the error in a bugreport.
-     *
-     * @hide
-     */
-    public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_ENABLE_ENCRYPTION_FAILED = 1114;
-
-    /**
-     * Indicates that disabling LE Audio Broadcast encryption failed
-     * <p>
-     * Example solution: Change parameters and try again. If error persists, the app can report
-     * telemetry and/or log the error in a bugreport.
-     *
-     * @hide
-     */
-    public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED = 1115;
-
-    /**
      * Indicates that there is already one device for which SCO audio is connected or connecting.
      *
      * @hide
@@ -370,6 +398,61 @@
     @SystemApi
     public static final int ERROR_CALL_ACTIVE = 1119;
 
+    // LE audio related return codes reserved from 1200 to 1300
+
+    /**
+     * Indicates that the broadcast ID cannot be found among existing Broadcast Sources.
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_LE_BROADCAST_INVALID_BROADCAST_ID = 1200;
+
+    /**
+     * Indicates that encryption code entered does not meet the specification requirement
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_LE_BROADCAST_INVALID_CODE = 1201;
+
+    /**
+     * Indicates that the source ID cannot be found in the given Broadcast sink device
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_LE_BROADCAST_ASSISTANT_INVALID_SOURCE_ID = 1202;
+
+    /**
+     * Indicates that the same Broadcast Source is already added to the Broadcast Sink
+     *
+     * Broadcast Source is identified by their advertising SID and broadcast ID
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_LE_BROADCAST_ASSISTANT_DUPLICATE_ADDITION = 1203;
+
+
+    /**
+     * Indicates that the program info in a {@link BluetoothLeAudioContentMetadata} is not valid
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_LE_CONTENT_METADATA_INVALID_PROGRAM_INFO = 1204;
+
+    /**
+     * Indicates that the language code in a {@link BluetoothLeAudioContentMetadata} is not valid
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_LE_CONTENT_METADATA_INVALID_LANGUAGE = 1205;
+
+    /**
+     * Indicates that operation failed due to other {@link BluetoothLeAudioContentMetadata} related
+     * issues not covered by other reason codes.
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_LE_CONTENT_METADATA_INVALID_OTHER = 1206;
+
     /**
      * Indicates that the RFCOMM listener could not be started due to the requested UUID already
      * being in use.
@@ -422,7 +505,7 @@
     public static final int RFCOMM_LISTENER_NO_SOCKET_AVAILABLE = 2005;
 
     /**
-     * Indicates that an unknown error has occurred has occurred.
+     * Indicates that an unknown error has occurred.
      */
     public static final int ERROR_UNKNOWN = Integer.MAX_VALUE;
 }