1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.bluetooth; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import android.bluetooth.le.AdvertiseData; 22 import android.bluetooth.le.AdvertisingSet; 23 import android.bluetooth.le.AdvertisingSetCallback; 24 import android.bluetooth.le.AdvertisingSetParameters; 25 import android.bluetooth.le.BluetoothLeAdvertiser; 26 import android.util.Log; 27 28 import androidx.core.util.Pair; 29 import androidx.test.core.app.ApplicationProvider; 30 import androidx.test.ext.junit.runners.AndroidJUnit4; 31 32 import com.android.compatibility.common.util.AdoptShellPermissionsRule; 33 34 import io.grpc.Deadline; 35 36 import org.junit.Ignore; 37 import org.junit.Rule; 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 41 import pandora.HostProto.ScanRequest; 42 import pandora.HostProto.ScanningResponse; 43 44 import java.util.Iterator; 45 import java.util.concurrent.CompletableFuture; 46 import java.util.concurrent.TimeUnit; 47 48 /** Test cases for {@link AdvertiseManager}. */ 49 @RunWith(AndroidJUnit4.class) 50 public class LeAdvertisingTest { 51 private static final String TAG = LeAdvertisingTest.class.getSimpleName(); 52 53 private static final int TIMEOUT_ADVERTISING_MS = 1000; 54 55 @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); 56 57 @Rule public final PandoraDevice mBumble = new PandoraDevice(); 58 59 @Test 60 @Ignore("b/343525982: Remove hidden api's dependencies to enable the test.") advertisingSet()61 public void advertisingSet() throws Exception { 62 Pair<String, Integer> addressPair = startAdvertising().join(); 63 ScanningResponse response = scanWithBumble(addressPair); 64 65 Log.i(TAG, "scan response: " + response); 66 assertThat(response).isNotNull(); 67 } 68 scanWithBumble(Pair<String, Integer> addressPair)69 private ScanningResponse scanWithBumble(Pair<String, Integer> addressPair) { 70 Log.d(TAG, "scanWithBumble"); 71 String address = addressPair.first; 72 int addressType = addressPair.second; 73 74 StreamObserverSpliterator<ScanningResponse> responseObserver = 75 new StreamObserverSpliterator<>(); 76 Deadline deadline = Deadline.after(TIMEOUT_ADVERTISING_MS, TimeUnit.MILLISECONDS); 77 mBumble.host() 78 .withDeadline(deadline) 79 .scan(ScanRequest.newBuilder().build(), responseObserver); 80 Iterator<ScanningResponse> responseObserverIterator = responseObserver.iterator(); 81 while (true) { 82 ScanningResponse scanningResponse = responseObserverIterator.next(); 83 String addr = 84 Utils.addressStringFromByteString( 85 addressType == AdvertisingSetParameters.ADDRESS_TYPE_PUBLIC 86 ? scanningResponse.getPublic() 87 : scanningResponse.getRandom()); 88 89 if (addr.equals(address)) { 90 return scanningResponse; 91 } 92 } 93 } 94 startAdvertising()95 private CompletableFuture<Pair<String, Integer>> startAdvertising() { 96 CompletableFuture<Pair<String, Integer>> future = 97 new CompletableFuture<Pair<String, Integer>>(); 98 99 android.content.Context context = ApplicationProvider.getApplicationContext(); 100 BluetoothManager bluetoothManager = context.getSystemService(BluetoothManager.class); 101 BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter(); 102 103 // Start advertising 104 BluetoothLeAdvertiser leAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser(); 105 AdvertisingSetParameters parameters = 106 new AdvertisingSetParameters.Builder() 107 .setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_RANDOM) 108 .build(); 109 AdvertiseData advertiseData = new AdvertiseData.Builder().build(); 110 AdvertiseData scanResponse = new AdvertiseData.Builder().build(); 111 AdvertisingSetCallback advertisingSetCallback = 112 new AdvertisingSetCallback() { 113 @Override 114 public void onAdvertisingSetStarted( 115 AdvertisingSet advertisingSet, int txPower, int status) { 116 Log.i( 117 TAG, 118 "onAdvertisingSetStarted " 119 + " txPower:" 120 + txPower 121 + " status:" 122 + status); 123 advertisingSet.enableAdvertising(true, TIMEOUT_ADVERTISING_MS, 0); 124 } 125 126 @Override 127 public void onOwnAddressRead( 128 AdvertisingSet advertisingSet, int addressType, String address) { 129 Log.i( 130 TAG, 131 "onOwnAddressRead " 132 + " addressType:" 133 + addressType 134 + " address:" 135 + address); 136 future.complete(new Pair<String, Integer>(address, addressType)); 137 } 138 139 @Override 140 public void onAdvertisingEnabled( 141 AdvertisingSet advertisingSet, boolean enabled, int status) { 142 Log.i( 143 TAG, 144 "onAdvertisingEnabled " 145 + " enabled:" 146 + enabled 147 + " status:" 148 + status); 149 advertisingSet.getOwnAddress(); 150 } 151 }; 152 leAdvertiser.startAdvertisingSet( 153 parameters, advertiseData, scanResponse, null, null, 0, 0, advertisingSetCallback); 154 155 return future; 156 } 157 } 158