Merge changes I96f7eb8f,If7629907,Icabe59ef,I8afaaf1c,I0a5ed3c2, ... into tm-qpr-dev

* changes:
  LeAudioTestApp: Allow for short broadcast codes
  Broadcaster: Handle short broadcast codes
  Bass: Handle short broadcast codes
  Bass: Fix reversed broadcast code
  LeAudioTestApp/Bass: Allow channel selection
  Bass: Fix BIS sync state channel map
diff --git a/android/app/jni/com_android_bluetooth_le_audio.cpp b/android/app/jni/com_android_bluetooth_le_audio.cpp
index c5cd514..87d7fb9 100644
--- a/android/app/jni/com_android_bluetooth_le_audio.cpp
+++ b/android/app/jni/com_android_bluetooth_le_audio.cpp
@@ -1130,10 +1130,17 @@
   std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
   if (!sLeAudioBroadcasterInterface) return;
 
-  std::array<uint8_t, 16> code_array{};
+  std::array<uint8_t, 16> code_array{0};
   if (broadcast_code) {
     jsize size = env->GetArrayLength(broadcast_code);
-    env->GetByteArrayRegion(broadcast_code, 0, size, (jbyte*)code_array.data());
+    if (size > 16) {
+      ALOGE("%s: broadcast code to long", __func__);
+      return;
+    }
+
+    // Padding with zeros on LSB positions if code is shorter than 16 octets
+    env->GetByteArrayRegion(broadcast_code, code_array.size() - size, size,
+                            (jbyte*)code_array.data());
   }
 
   jbyte* meta = env->GetByteArrayElements(metadata, nullptr);
diff --git a/android/app/src/com/android/bluetooth/bass_client/BassClientService.java b/android/app/src/com/android/bluetooth/bass_client/BassClientService.java
index d74aaf6..298eca0 100755
--- a/android/app/src/com/android/bluetooth/bass_client/BassClientService.java
+++ b/android/app/src/com/android/bluetooth/bass_client/BassClientService.java
@@ -1041,6 +1041,7 @@
             return;
         }
 
+        byte[] code = sourceMetadata.getBroadcastCode();
         for (BluetoothDevice device : devices) {
             BassClientStateMachine stateMachine = getOrCreateStateMachine(device);
             if (stateMachine == null) {
@@ -1070,6 +1071,15 @@
                         BluetoothStatusCodes.ERROR_LE_BROADCAST_ASSISTANT_DUPLICATE_ADDITION);
                 continue;
             }
+            if ((code != null) && (code.length != 0)) {
+                if ((code.length > 16) || (code.length < 4)) {
+                    log("Invalid broadcast code length: " + code.length
+                            + ", should be between 4 and 16 octets");
+                    mCallbacks.notifySourceAddFailed(device, sourceMetadata,
+                            BluetoothStatusCodes.ERROR_BAD_PARAMETERS);
+                    continue;
+                }
+            }
 
             if (isGroupOp) {
                 enqueueSourceGroupOp(device, BassClientStateMachine.ADD_BCAST_SOURCE,
@@ -1104,6 +1114,7 @@
             return;
         }
 
+        byte[] code = updatedMetadata.getBroadcastCode();
         for (Map.Entry<BluetoothDevice, Integer> deviceSourceIdPair : devices.entrySet()) {
             BluetoothDevice device = deviceSourceIdPair.getKey();
             Integer deviceSourceId = deviceSourceIdPair.getValue();
@@ -1127,6 +1138,15 @@
                         BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR);
                 continue;
             }
+            if ((code != null) && (code.length != 0)) {
+                if ((code.length > 16) || (code.length < 4)) {
+                    log("Invalid broadcast code length: " + code.length
+                            + ", should be between 4 and 16 octets");
+                    mCallbacks.notifySourceModifyFailed(device, sourceId,
+                            BluetoothStatusCodes.ERROR_BAD_PARAMETERS);
+                    continue;
+                }
+            }
             if (stateMachine.hasPendingSourceOperation()) {
                 throw new IllegalStateException("modifySource: source operation already pending");
             }
diff --git a/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java b/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java
index 9e5206c..fda4b8e 100755
--- a/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java
+++ b/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java
@@ -1225,7 +1225,11 @@
         int bisSync = 0;
         for (BluetoothLeBroadcastChannel channel : channels) {
             if (channel.isSelected()) {
-                bisSync |= 1 << channel.getChannelIndex();
+                if (channel.getChannelIndex() == 0) {
+                    Log.e(TAG, "getBisSyncFromChannelPreference: invalid channel index=0");
+                    continue;
+                }
+                bisSync |= 1 << (channel.getChannelIndex() - 1);
             }
         }
 
@@ -1290,16 +1294,6 @@
             stream.write(metadata.getRawMetadata(), 0, metadata.getRawMetadata().length);
         }
 
-        if (metaData.isEncrypted() && metaData.getBroadcastCode().length == 16) {
-            if (metaData.getBroadcastCode().length != 16) {
-                Log.e(TAG, "Delivered invalid length of broadcast code: " +
-                      metaData.getBroadcastCode().length + ", should be 16");
-                return null;
-            }
-
-            mSetBroadcastCodePending = true;
-        }
-
         byte[] res = stream.toByteArray();
         log("ADD_BCAST_SOURCE in Bytes");
         BassUtils.printByteArray(res);
@@ -1398,10 +1392,8 @@
                     + recvState.getSourceId());
             return null;
         }
-        // Can Keep as ASCII as is
-        String reversePIN = new StringBuffer(new String(metaData.getBroadcastCode()))
-                .reverse().toString();
-        byte[] actualPIN = reversePIN.getBytes();
+        // Broadcast Code
+        byte[] actualPIN = metaData.getBroadcastCode();
         if (actualPIN == null) {
             Log.e(TAG, "actual PIN is null");
             return null;
@@ -1409,6 +1401,8 @@
             log("byte array broadcast Code:" + Arrays.toString(actualPIN));
             log("pinLength:" + actualPIN.length);
             // Broadcast_Code, Fill the PIN code in the Last Position
+            // This effectively adds padding zeros to LSB positions when the broadcast code
+            // is shorter than 16 octets
             System.arraycopy(
                     actualPIN, 0, res,
                     (BassConstants.PIN_CODE_CMD_LEN - actualPIN.length), actualPIN.length);
@@ -1545,6 +1539,9 @@
                         mBluetoothGatt.writeCharacteristic(mBroadcastScanControlPoint);
                         mPendingOperation = message.what;
                         mPendingMetadata = metaData;
+                        if (metaData.isEncrypted() && (metaData.getBroadcastCode() != null)) {
+                            mSetBroadcastCodePending = true;
+                        }
                         transitionTo(mConnectedProcessing);
                         sendMessageDelayed(GATT_TXN_TIMEOUT, BassConstants.GATT_TXN_TIMEOUT_MS);
                     } else {
@@ -1572,6 +1569,9 @@
                         if (paSync == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE) {
                             setPendingRemove(sourceId, true);
                         }
+                        if (metaData.isEncrypted() && (metaData.getBroadcastCode() != null)) {
+                            mSetBroadcastCodePending = true;
+                        }
                         mPendingMetadata = metaData;
                         transitionTo(mConnectedProcessing);
                         sendMessageDelayed(GATT_TXN_TIMEOUT, BassConstants.GATT_TXN_TIMEOUT_MS);
diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
index bc7d108..7663900 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
@@ -664,6 +664,15 @@
             Log.w(TAG, "Native interface not available.");
             return;
         }
+        boolean isEncrypted = (broadcastCode != null) && (broadcastCode.length != 0);
+        if (isEncrypted) {
+            if ((broadcastCode.length > 16) || (broadcastCode.length < 4)) {
+                Log.e(TAG, "Invalid broadcast code length. Should be from 4 to 16 octets long.");
+                return;
+            }
+        }
+
+        Log.i(TAG, "createBroadcast: isEncrypted=" + (isEncrypted ? "true" : "false"));
         mLeAudioBroadcasterNativeInterface.createBroadcast(metadata.getRawMetadata(),
                 broadcastCode);
     }
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java
index 9568d4b..d74b622 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java
@@ -299,7 +299,7 @@
     @Test
     public void testCreateBroadcastNative() {
         int broadcastId = 243;
-        byte[] code = {0x00, 0x01, 0x00};
+        byte[] code = {0x00, 0x01, 0x00, 0x02};
 
         mService.mBroadcastCallbacks.register(mCallbacks);
 
@@ -314,7 +314,7 @@
     @Test
     public void testCreateBroadcastNativeFailed() {
         int broadcastId = 243;
-        byte[] code = {0x00, 0x01, 0x00};
+        byte[] code = {0x00, 0x01, 0x00, 0x02};
 
         mService.mBroadcastCallbacks.register(mCallbacks);
 
@@ -340,7 +340,7 @@
     @Test
     public void testStartStopBroadcastNative() {
         int broadcastId = 243;
-        byte[] code = {0x00, 0x01, 0x00};
+        byte[] code = {0x00, 0x01, 0x00, 0x02};
 
         mService.mBroadcastCallbacks.register(mCallbacks);
 
diff --git a/android/leaudio/app/src/main/java/com/android/bluetooth/leaudio/BroadcastScanActivity.java b/android/leaudio/app/src/main/java/com/android/bluetooth/leaudio/BroadcastScanActivity.java
index 1af0d22..0b2eb4c 100644
--- a/android/leaudio/app/src/main/java/com/android/bluetooth/leaudio/BroadcastScanActivity.java
+++ b/android/leaudio/app/src/main/java/com/android/bluetooth/leaudio/BroadcastScanActivity.java
@@ -19,7 +19,9 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastChannel;
 import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastSubgroup;
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.LayoutInflater;
@@ -36,6 +38,7 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import java.util.Objects;
+import java.util.List;
 
 
 public class BroadcastScanActivity extends AppCompatActivity {
@@ -85,6 +88,10 @@
                 View alertView =
                         inflater.inflate(R.layout.broadcast_scan_add_encrypted_source_dialog,
                                          null);
+
+                final EditText channels_input_text =
+                        alertView.findViewById(R.id.broadcast_channel_map);
+
                 final EditText code_input_text =
                         alertView.findViewById(R.id.broadcast_code_input);
                 BluetoothLeBroadcastMetadata.Builder builder = new
@@ -105,7 +112,8 @@
                                        + broadcastId, Toast.LENGTH_SHORT).show();
                         metadata = builder.setEncrypted(false).build();
                     } else {
-                        if (code_input_text.getText().length() != 16) {
+                        if ((code_input_text.getText().length() > 16) ||
+                                (code_input_text.getText().length() < 4)) {
                             Toast.makeText(recyclerView.getContext(),
                                            "Invalid Broadcast code length",
                                            Toast.LENGTH_SHORT).show();
@@ -119,6 +127,27 @@
                                .build();
                     }
 
+                    if ((channels_input_text.getText() != null)
+                            && (channels_input_text.getText().length() != 0)) {
+                        int channelMap = Integer.parseInt(channels_input_text.getText().toString());
+                        // Apply a single channel map preference to all subgroups
+                        for (BluetoothLeBroadcastSubgroup subGroup : metadata.getSubgroups()) {
+                            List<BluetoothLeBroadcastChannel> channels = subGroup.getChannels();
+                            for (int i = 0; i < channels.size(); i++) {
+                                BluetoothLeBroadcastChannel channel = channels.get(i);
+                                // Set the channel preference value according to the map
+                                if (channel.getChannelIndex() != 0) {
+                                    if ((channelMap & (1 << (channel.getChannelIndex() - 1))) != 0) {
+                                        BluetoothLeBroadcastChannel.Builder bob
+                                                = new BluetoothLeBroadcastChannel.Builder(channel);
+                                        bob.setSelected(true);
+                                        channels.set(i, bob.build());
+                                    }
+                                }
+                            }
+                        }
+                    }
+
                     Toast.makeText(recyclerView.getContext(), "Adding broadcast source"
                                     + " broadcastId=" + broadcastId, Toast.LENGTH_SHORT).show();
                     mViewModel.addBroadcastSource(device, metadata);
diff --git a/android/leaudio/app/src/main/res/layout/broadcast_scan_add_encrypted_source_dialog.xml b/android/leaudio/app/src/main/res/layout/broadcast_scan_add_encrypted_source_dialog.xml
index 16d765e..d2e7459 100644
--- a/android/leaudio/app/src/main/res/layout/broadcast_scan_add_encrypted_source_dialog.xml
+++ b/android/leaudio/app/src/main/res/layout/broadcast_scan_add_encrypted_source_dialog.xml
@@ -29,4 +29,25 @@
             android:inputType="textMultiLine|textFilter" />
     </LinearLayout>
 
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/textViewChannelMap"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="Channel Map:" />
+        <EditText
+            android:id="@+id/broadcast_channel_map"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="2"
+            android:digits="123456789"
+            android:inputType="number"
+            android:maxLength="3"/>
+    </LinearLayout>
+
 </LinearLayout>