Skip to content

Commit

Permalink
Snap for 11220357 from 4b6c37a to 24Q1-release
Browse files Browse the repository at this point in the history
Change-Id: I172f2530f8a34cb624f77b523260581a889e18ec
  • Loading branch information
Android Build Coastguard Worker committed Dec 15, 2023
2 parents 281ff81 + 4b6c37a commit 2fb073d
Show file tree
Hide file tree
Showing 34 changed files with 497 additions and 232 deletions.
1 change: 1 addition & 0 deletions android/app/OWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
Expand Down
13 changes: 5 additions & 8 deletions android/app/jni/com_android_bluetooth_le_audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1045,16 +1045,14 @@ jobject prepareBluetoothLeBroadcastMetadataObject(
return nullptr;
}

// Skip the leading null char bytes
// Remove the ending null char bytes
int nativeCodeSize = 16;
int nativeCodeLeadingZeros = 0;
if (broadcast_metadata.broadcast_code) {
auto& nativeCode = broadcast_metadata.broadcast_code.value();
nativeCodeLeadingZeros =
nativeCodeSize =
std::find_if(nativeCode.cbegin(), nativeCode.cend(),
[](int x) { return x != 0x00; }) -
[](int x) { return x == 0x00; }) -
nativeCode.cbegin();
nativeCodeSize = nativeCode.size() - nativeCodeLeadingZeros;
}

ScopedLocalRef<jbyteArray> code(env, env->NewByteArray(nativeCodeSize));
Expand All @@ -1066,8 +1064,7 @@ jobject prepareBluetoothLeBroadcastMetadataObject(
if (broadcast_metadata.broadcast_code) {
env->SetByteArrayRegion(
code.get(), 0, nativeCodeSize,
(const jbyte*)broadcast_metadata.broadcast_code->data() +
nativeCodeLeadingZeros);
(const jbyte*)broadcast_metadata.broadcast_code->data());
CHECK(!env->ExceptionCheck());
}

Expand Down Expand Up @@ -1107,7 +1104,7 @@ jobject prepareBluetoothLeBroadcastMetadataObject(
broadcast_metadata.broadcast_code ? true : false,
broadcast_metadata.is_public, broadcast_name.get(),
broadcast_metadata.broadcast_code ? code.get() : nullptr,
(jint)broadcast_metadata.basic_audio_announcement.presentation_delay,
(jint)broadcast_metadata.basic_audio_announcement.presentation_delay_us,
audio_cfg_quality, (jint)bluetooth::le_audio::kLeAudioSourceRssiUnknown,
public_meta_obj.get(), subgroup_list_obj.get());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,6 @@ boolean getAdapterProperty(int type) {
return getAdapterPropertyNative(type);
}

boolean setAdapterProperty(int type) {
return setAdapterPropertyNative(type);
}

boolean setDeviceProperty(byte[] address, int type, byte[] val) {
return setDevicePropertyNative(address, type, val);
}
Expand Down Expand Up @@ -276,8 +272,6 @@ private native boolean initNative(

private native boolean getAdapterPropertyNative(int type);

private native boolean setAdapterPropertyNative(int type);

private native boolean setDevicePropertyNative(byte[] address, int type, byte[] val);

private native boolean getDevicePropertyNative(byte[] address, int type);
Expand Down
1 change: 1 addition & 0 deletions framework/tests/bumble/Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ android_test_helper_app {
"compatibility-device-util-axt",
"grpc-java-lite",
"grpc-java-okhttp-client-lite",
"mockito-kotlin2",
"opencensus-java-contrib-grpc-metrics",
"pandora_experimental-grpc-java",
"pandora_experimental-proto-java",
Expand Down
69 changes: 43 additions & 26 deletions framework/tests/bumble/src/android/bluetooth/DckTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,21 @@ import java.util.concurrent.TimeUnit
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.any
import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
import org.mockito.Mockito.timeout
import org.mockito.Mockito.verify
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.timeout
import org.mockito.kotlin.verify
import pandora.HostProto.AdvertiseRequest
import pandora.HostProto.OwnAddressType

@RunWith(AndroidJUnit4::class)
public class DckTest {
private val TAG = "DckTest"
private val TIMEOUT: Long = 2000

private val context: Context = ApplicationProvider.getApplicationContext()
private val bluetoothManager = context.getSystemService(BluetoothManager::class.java)!!
private val bluetoothAdapter = bluetoothManager.adapter

// CCC DK Specification R3 1.2.0 r14 section 19.2.1.2 Bluetooth Le Pairing
private val CCC_DK_UUID = UUID.fromString("0000FFF5-0000-1000-8000-00805f9b34fb")

// A Rule live from a test setup through it's teardown.
// Gives shell permissions during the test.
@Rule @JvmField val mPermissionRule = AdoptShellPermissionsRule()
Expand All @@ -62,18 +57,23 @@ public class DckTest {
*
* <p>This test method goes through the following steps:
* <ul>
* <li>1. Register the Dck Gatt service on Bumble over a gRPC call.</li>
* <li>2. Advertises the host's (potentially the car's) Bluetooth capabilities through a gRPC call.</li>
* <li>3. Fetches a remote LE (Low Energy) Bluetooth device instance.</li>
* <li>4. Sets up a mock GATT callback for Bluetooth related events.</li>
* <li>5. Connects to the Bumble device and verifies a successful connection.</li>
* <li>6. Discovers the GATT services offered by Bumble and checks for a successful service discovery.</li>
* <li>7. Validates the presence of the required GATT service (CCC_DK_UUID) on the Bumble device.</li>
* <li>8. Disconnects from the Bumble device and ensures a successful disconnection.</li>
* <li>1. Register the Dck Gatt service on Bumble over a gRPC call.</li>
* <li>2. Advertises the host's (potentially the car's) Bluetooth capabilities through a gRPC
* call.</li>
* <li>3. Fetches a remote LE (Low Energy) Bluetooth device instance.</li>
* <li>4. Sets up a mock GATT callback for Bluetooth related events.</li>
* <li>5. Connects to the Bumble device and verifies a successful connection.</li>
* <li>6. Discovers the GATT services offered by Bumble and checks for a successful service
* discovery.</li>
* <li>7. Validates the presence of the required GATT service (CCC_DK_UUID) on the Bumble
* device.</li>
* <li>8. Disconnects from the Bumble device and ensures a successful disconnection.</li>
* </ul>
*
* </p>
*
* @throws AssertionError if any of the assertions (like service discovery or connection checks) fail.
* @throws AssertionError if any of the assertions (like service discovery or connection checks)
* fail.
* @see BluetoothGatt
* @see BluetoothGattCallback
*/
Expand All @@ -99,24 +99,33 @@ public class DckTest {
.hostBlocking()
.advertise(
AdvertiseRequest.newBuilder()
.setLegacy(true) // As of now, Bumble only support legacy advertising (b/266124496).
.setLegacy(
true
) // As of now, Bumble only support legacy advertising (b/266124496).
.setConnectable(true)
.setOwnAddressType(OwnAddressType.RANDOM) // Ask Bumble to advertise it's `RANDOM` address.
.setOwnAddressType(
OwnAddressType.RANDOM
) // Ask Bumble to advertise it's `RANDOM` address.
.build()
)

// 3. Fetch a remote Bluetooth device instance (here, Bumble).
val bumbleDevice =
bluetoothAdapter.getRemoteLeDevice(
// To keep things straightforward, the Bumble RANDOM address is set to a predefined constant.
// Typically, an LE scan would be conducted to identify the Bumble device, matching it based on its
// To keep things straightforward, the Bumble RANDOM address is set to a predefined
// constant.
// Typically, an LE scan would be conducted to identify the Bumble device, matching
// it based on its
// Advertising data.
Utils.BUMBLE_RANDOM_ADDRESS,
BluetoothDevice.ADDRESS_TYPE_RANDOM // Specify address type as RANDOM because the device advertises with this address type.
BluetoothDevice
.ADDRESS_TYPE_RANDOM // Specify address type as RANDOM because the device
// advertises with this address type.
)

// 4. Create a mock callback to handle Bluetooth GATT (Generic Attribute Profile) related events.
val gattCallback = mock(BluetoothGattCallback::class.java)
// 4. Create a mock callback to handle Bluetooth GATT (Generic Attribute Profile) related
// events.
val gattCallback = mock<BluetoothGattCallback>()

// 5. Connect to the Bumble device and expect a successful connection callback.
var bumbleGatt = bumbleDevice.connectGatt(context, false, gattCallback)
Expand Down Expand Up @@ -144,4 +153,12 @@ public class DckTest {
eq(BluetoothProfile.STATE_DISCONNECTED)
)
}

companion object {
private const val TAG = "DckTest"
private const val TIMEOUT: Long = 2000

// CCC DK Specification R3 1.2.0 r14 section 19.2.1.2 Bluetooth Le Pairing
private val CCC_DK_UUID = UUID.fromString("0000FFF5-0000-1000-8000-00805f9b34fb")
}
}
79 changes: 71 additions & 8 deletions framework/tests/bumble/src/android/bluetooth/LeScanningTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,24 @@

import com.android.compatibility.common.util.AdoptShellPermissionsRule;

import com.google.protobuf.ByteString;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;

import pandora.HostProto;
import pandora.HostProto.AdvertiseRequest;
import pandora.HostProto.AdvertiseResponse;
import pandora.HostProto.OwnAddressType;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import pandora.HostProto;
import pandora.HostProto.AdvertiseRequest;
import pandora.HostProto.AdvertiseResponse;
import pandora.HostProto.OwnAddressType;

@RunWith(AndroidJUnit4.class)
public class LeScanningTest {
private static final String TAG = "LeScanningTest";
Expand Down Expand Up @@ -289,6 +291,57 @@ public void startBleScan_oneTooManyScansFails() {
mLeScanner.stopScan(lastMockScanCallback);
}

@Test
public void startBleScan_withNonConnectablePublicAdvertisement() {
AdvertiseRequest.Builder requestBuilder =
AdvertiseRequest.newBuilder()
.setConnectable(false)
.setOwnAddressType(OwnAddressType.PUBLIC);
advertiseWithBumble(requestBuilder);

ScanFilter scanFilter =
new ScanFilter.Builder()
.setDeviceAddress(mBumble.getRemoteDevice().getAddress())
.build();

List<ScanResult> results =
startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES);

assertThat(results).isNotNull();
assertThat(results.get(0).isConnectable()).isFalse();
assertThat(results.get(1).isConnectable()).isFalse();
}

@Test
public void startBleScan_withNonConnectableScannablePublicAdvertisement() {
byte[] payload = {0x02, 0x03};
// first 2 bytes are the manufacturer ID 0x00E0 (Google) in little endian
byte[] manufacturerData = {(byte) 0xE0, 0x00, payload[0], payload[1]};
HostProto.DataTypes.Builder scanResponse =
HostProto.DataTypes.newBuilder()
.setManufacturerSpecificData(ByteString.copyFrom(manufacturerData));

AdvertiseRequest.Builder requestBuilder =
AdvertiseRequest.newBuilder()
.setConnectable(false)
.setOwnAddressType(OwnAddressType.PUBLIC)
.setScanResponseData(scanResponse);
advertiseWithBumble(requestBuilder);

ScanFilter scanFilter =
new ScanFilter.Builder()
.setDeviceAddress(mBumble.getRemoteDevice().getAddress())
.build();

List<ScanResult> results =
startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES);

assertThat(results).isNotNull();
assertThat(results.get(0).isConnectable()).isFalse();
assertThat(results.get(0).getScanRecord().getManufacturerSpecificData(0x00E0))
.isEqualTo(payload);
}

private List<ScanResult> startScanning(ScanFilter scanFilter, int callbackType) {
CompletableFuture<List<ScanResult>> future = new CompletableFuture<>();
List<ScanResult> scanResults = new ArrayList<>();
Expand All @@ -306,7 +359,11 @@ public void onScanResult(int callbackType, ScanResult result) {
Log.i(
TAG,
"onScanResult "
+ "callbackType: "
+ "address: "
+ result.getDevice().getAddress()
+ ", connectable: "
+ result.isConnectable()
+ ", callbackType: "
+ callbackType
+ ", service uuids: "
+ result.getScanRecord().getServiceUuids());
Expand Down Expand Up @@ -342,17 +399,23 @@ public void onScanFailed(int errorCode) {

private void advertiseWithBumble(String serviceUuid, OwnAddressType addressType) {
AdvertiseRequest.Builder requestBuilder =
AdvertiseRequest.newBuilder().setLegacy(true).setOwnAddressType(addressType);
AdvertiseRequest.newBuilder().setOwnAddressType(addressType);

if (serviceUuid != null) {
HostProto.DataTypes.Builder dataTypeBuilder = HostProto.DataTypes.newBuilder();
dataTypeBuilder.addCompleteServiceClassUuids128(serviceUuid);
requestBuilder.setData(dataTypeBuilder.build());
}

advertiseWithBumble(requestBuilder);
}

private void advertiseWithBumble(AdvertiseRequest.Builder requestBuilder) {
// Bumble currently only supports legacy advertising.
requestBuilder.setLegacy(true);
// Collect and ignore responses.
StreamObserverSpliterator<AdvertiseResponse> responseObserver =
new StreamObserverSpliterator<>();

mBumble.host().advertise(requestBuilder.build(), responseObserver);
}
}
Loading

0 comments on commit 2fb073d

Please sign in to comment.