Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e3362c9 authored by David Duarte's avatar David Duarte Committed by Automerger Merge Worker
Browse files

Merge changes I69d0d9ed,I23d9badc into main am: 11a3bcfd am: 62ef8cd5

parents 57993d2f 62ef8cd5
Loading
Loading
Loading
Loading
+43 −52
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 static android.bluetooth.Utils.factoryResetAndCreateNewChannel;
import static com.google.common.truth.Truth.assertThat;

import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertisingSet;
@@ -14,69 +30,41 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import static com.google.common.truth.Truth.assertThat;
import com.google.protobuf.Empty;

import io.grpc.Context.CancellableContext;
import io.grpc.Deadline;
import io.grpc.ManagedChannel;
import io.grpc.stub.StreamObserver;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import pandora.HostGrpc;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import pandora.HostProto.ScanRequest;
import pandora.HostProto.ScanningResponse;


/**
 * Test cases for {@link AdvertiseManager}.
 */
/** Test cases for {@link AdvertiseManager}. */
@RunWith(AndroidJUnit4.class)
public class LeAdvertisingTest {

    private static final String TAG = "LeAdvertisingTest";

    private static final int TIMEOUT_ADVERTISING_MS = 1000;

    private static ManagedChannel mChannel;

    private static HostGrpc.HostBlockingStub mHostBlockingStub;

    private static HostGrpc.HostStub mHostStub;
    @Rule public final PandoraDevice mBumble = new PandoraDevice();

    @BeforeClass
    public static void setUpClass() throws Exception {
        InstrumentationRegistry.getInstrumentation().getUiAutomation()
        InstrumentationRegistry.getInstrumentation()
                .getUiAutomation()
                .adoptShellPermissionIdentity();
    }

    @Before
    public void setUp() throws Exception {
        // Cleanup previous channels and create a new channel for all successive grpc calls
        mChannel = factoryResetAndCreateNewChannel();

        mHostBlockingStub = HostGrpc.newBlockingStub(mChannel);
        mHostStub = HostGrpc.newStub(mChannel);
        mHostBlockingStub.withWaitForReady().readLocalAddress(Empty.getDefaultInstance());
    }

    @After
    public void tearDown() throws Exception {
        // terminate the channel
        mChannel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
    }

    @Test
    public void advertisingSet() throws Exception {
        ScanningResponse response = startAdvertising()
        ScanningResponse response =
                startAdvertising()
                        .thenCompose(advAddressPair -> scanWithBumble(advAddressPair))
                        .join();

@@ -94,8 +82,10 @@ public class LeAdvertisingTest {

        // Start advertising
        BluetoothLeAdvertiser leAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
        AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder().
             setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_RANDOM).build();
        AdvertisingSetParameters parameters =
                new AdvertisingSetParameters.Builder()
                        .setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_RANDOM)
                        .build();
        AdvertiseData advertiseData = new AdvertiseData.Builder().build();
        AdvertiseData scanResponse = new AdvertiseData.Builder().build();
        AdvertisingSetCallback advertisingSetCallback =
@@ -139,8 +129,8 @@ public class LeAdvertisingTest {
                        advertisingSet.getOwnAddress();
                    }
                };
        leAdvertiser.startAdvertisingSet(parameters, advertiseData, scanResponse,
          null, null, 0, 0, advertisingSetCallback);
        leAdvertiser.startAdvertisingSet(
                parameters, advertiseData, scanResponse, null, null, 0, 0, advertisingSetCallback);

        return future;
    }
@@ -184,10 +174,11 @@ public class LeAdvertisingTest {
                };

        Deadline initialDeadline = Deadline.after(TIMEOUT_ADVERTISING_MS, TimeUnit.MILLISECONDS);
        withCancellation.run(() -> mHostStub.withDeadline(initialDeadline)
            .scan(request, responseObserver));
        withCancellation.run(
                () -> mBumble.host().withDeadline(initialDeadline).scan(request, responseObserver));

        return future.whenComplete((input, exception) -> {
        return future.whenComplete(
                (input, exception) -> {
                    withCancellation.cancel(null);
                });
    }
+27 −51
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package android.bluetooth;

import static android.bluetooth.Utils.factoryResetAndCreateNewChannel;

import static com.google.common.truth.Truth.assertThat;

import android.bluetooth.le.BluetoothLeScanner;
@@ -32,12 +30,11 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import com.google.protobuf.Empty;
import io.grpc.stub.StreamObserver;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

@@ -46,10 +43,6 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import io.grpc.ManagedChannel;
import io.grpc.stub.StreamObserver;

import pandora.HostGrpc;
import pandora.HostProto;
import pandora.HostProto.AdvertiseRequest;
import pandora.HostProto.AdvertiseResponse;
@@ -59,11 +52,7 @@ public class LeScanningTest {
    private static final String TAG = "LeScanningTest";
    private static final int TIMEOUT_SCANNING_MS = 2000;

    private static ManagedChannel mChannel;

    private static HostGrpc.HostBlockingStub mHostBlockingStub;

    private static HostGrpc.HostStub mHostStub;
    @Rule public final PandoraDevice mBumble = new PandoraDevice();

    private final String TEST_UUID_STRING = "00001805-0000-1000-8000-00805f9b34fb";

@@ -74,22 +63,6 @@ public class LeScanningTest {
                .adoptShellPermissionIdentity();
    }

    @Before
    public void setUp() throws Exception {
        // Cleanup previous channels and create a new channel for all successive grpc calls
        mChannel = factoryResetAndCreateNewChannel();

        mHostBlockingStub = HostGrpc.newBlockingStub(mChannel);
        mHostStub = HostGrpc.newStub(mChannel);
        mHostBlockingStub.withWaitForReady().readLocalAddress(Empty.getDefaultInstance());
    }

    @After
    public void tearDown() throws Exception {
        // terminate the channel
        mChannel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
        InstrumentationRegistry.getInstrumentation()
@@ -101,17 +74,17 @@ public class LeScanningTest {
    public void startBleScan_withCallbackTypeAllMatches() {
        advertiseWithBumble(TEST_UUID_STRING);

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

        assertThat(results.get(0).getScanRecord().getServiceUuids().get(0)).isEqualTo(
                ParcelUuid.fromString(TEST_UUID_STRING));
        assertThat(results.get(1).getScanRecord().getServiceUuids().get(0)).isEqualTo(
                ParcelUuid.fromString(TEST_UUID_STRING));
        assertThat(results.get(0).getScanRecord().getServiceUuids().get(0))
                .isEqualTo(ParcelUuid.fromString(TEST_UUID_STRING));
        assertThat(results.get(1).getScanRecord().getServiceUuids().get(0))
                .isEqualTo(ParcelUuid.fromString(TEST_UUID_STRING));
    }

    private CompletableFuture<List<ScanResult>> startScanning(String serviceUuid,
            int callbackType) {
    private CompletableFuture<List<ScanResult>> startScanning(
            String serviceUuid, int callbackType) {
        CompletableFuture<List<ScanResult>> future = new CompletableFuture<>();
        List<ScanResult> scanResults = new ArrayList<>();

@@ -129,17 +102,21 @@ public class LeScanningTest {
                        .build();

        List<ScanFilter> scanFilters = new ArrayList<>();
        ScanFilter scanFilter = new ScanFilter.Builder()
                .setServiceUuid(ParcelUuid.fromString(serviceUuid))
                .build();
        ScanFilter scanFilter =
                new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(serviceUuid)).build();
        scanFilters.add(scanFilter);

        ScanCallback scanCallback =
                new ScanCallback() {
                    @Override
                    public void onScanResult(int callbackType, ScanResult result) {
                        Log.i(TAG, "onScanResult " + "callbackType: " + callbackType
                                + ", service uuids: " + result.getScanRecord().getServiceUuids());
                        Log.i(
                                TAG,
                                "onScanResult "
                                        + "callbackType: "
                                        + callbackType
                                        + ", service uuids: "
                                        + result.getScanRecord().getServiceUuids());
                        if (scanResults.size() < 2) {
                            scanResults.add(result);
                        } else {
@@ -161,14 +138,13 @@ public class LeScanningTest {
    }

    private void advertiseWithBumble(String serviceUuid) {
        HostProto.DataTypes dataType = HostProto.DataTypes.newBuilder()
        HostProto.DataTypes dataType =
                HostProto.DataTypes.newBuilder()
                        .addCompleteServiceClassUuids128(serviceUuid)
                        .build();

        AdvertiseRequest request = AdvertiseRequest.newBuilder()
                .setLegacy(true)
                .setData(dataType)
                .build();
        AdvertiseRequest request =
                AdvertiseRequest.newBuilder().setLegacy(true).setData(dataType).build();

        StreamObserver<AdvertiseResponse> responseObserver =
                new StreamObserver<>() {
@@ -188,6 +164,6 @@ public class LeScanningTest {
                    }
                };

        mHostStub.advertise(request, responseObserver);
        mBumble.host().advertise(request, responseObserver);
    }
}
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.util.Log;

import com.google.protobuf.Empty;

import io.grpc.ManagedChannel;
import io.grpc.okhttp.OkHttpChannelBuilder;

import org.junit.rules.ExternalResource;

import java.util.concurrent.TimeUnit;

import pandora.HostGrpc;

public final class PandoraDevice extends ExternalResource {
    private static final String TAG = PandoraDevice.class.getSimpleName();

    private final String mAddress;
    private final int mPort;

    private ManagedChannel mChannel;

    public PandoraDevice(String address, int port) {
        mAddress = address;
        mPort = port;
    }

    public PandoraDevice() {
        this("localhost", 7999);
    }

    @Override
    protected void before() {
        Log.i(TAG, "factoryReset");
        // FactoryReset is killing the server and restarting all channels created before the server
        // restarted that cannot be reused
        ManagedChannel channel =
                OkHttpChannelBuilder.forAddress(mAddress, mPort).usePlaintext().build();

        HostGrpc.HostBlockingStub stub = HostGrpc.newBlockingStub(channel);
        stub.factoryReset(Empty.getDefaultInstance());

        try {
            // terminate the channel
            channel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        mChannel = OkHttpChannelBuilder.forAddress(mAddress, mPort).usePlaintext().build();
        stub = HostGrpc.newBlockingStub(mChannel);

        stub.withWaitForReady().readLocalAddress(Empty.getDefaultInstance());
    }

    @Override
    protected void after() {
        Log.i(TAG, "shutdown");
        try {
            // terminate the channel
            mChannel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
            mChannel = null;
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /** Get Pandora Host service */
    public HostGrpc.HostStub host() {
        return HostGrpc.newStub(mChannel);
    }
}
+17 −26
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 com.google.protobuf.ByteString;
import com.google.protobuf.Empty;

import java.util.concurrent.TimeUnit;

import io.grpc.ManagedChannel;
import io.grpc.okhttp.OkHttpChannelBuilder;
import pandora.HostGrpc;

public final class Utils {
    public static String addressStringFromByteString(ByteString bs) {
@@ -20,22 +29,4 @@ public final class Utils {
        }
        return refAddrBuilder.toString();
    }

    public static ManagedChannel factoryResetAndCreateNewChannel() throws InterruptedException {
        // FactoryReset is killing the server and restarting all channels created before the server
        // restarted that cannot be reused
        ManagedChannel channel = OkHttpChannelBuilder
                .forAddress("localhost", 7999)
                .usePlaintext()
                .build();

        HostGrpc.HostBlockingStub stub = HostGrpc.newBlockingStub(channel);
        stub.factoryReset(Empty.getDefaultInstance());

        // terminate the channel
        channel.shutdown().awaitTermination(1, TimeUnit.SECONDS);

        // return new channel for future use
        return OkHttpChannelBuilder.forAddress("localhost", 7999).usePlaintext().build();
    }
}