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>