Merge "Support AdvertisingSet for Bluetooth5.0"
diff --git a/nearby/service/java/com/android/server/nearby/provider/BleBroadcastProvider.java b/nearby/service/java/com/android/server/nearby/provider/BleBroadcastProvider.java
index 2a79250..8537872 100644
--- a/nearby/service/java/com/android/server/nearby/provider/BleBroadcastProvider.java
+++ b/nearby/service/java/com/android/server/nearby/provider/BleBroadcastProvider.java
@@ -16,16 +16,23 @@
package com.android.server.nearby.provider;
+import static com.android.server.nearby.NearbyService.TAG;
import static com.android.server.nearby.presence.PresenceConstants.PRESENCE_UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.AdvertisingSet;
+import android.bluetooth.le.AdvertisingSetCallback;
+import android.bluetooth.le.AdvertisingSetParameters;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.nearby.BroadcastCallback;
+import android.nearby.BroadcastRequest;
import android.os.ParcelUuid;
+import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.nearby.injector.Injector;
import java.util.concurrent.Executor;
@@ -47,13 +54,16 @@
private BroadcastListener mBroadcastListener;
private boolean mIsAdvertising;
-
+ @VisibleForTesting
+ AdvertisingSetCallback mAdvertisingSetCallback;
BleBroadcastProvider(Injector injector, Executor executor) {
mInjector = injector;
mExecutor = executor;
+ mAdvertisingSetCallback = getAdvertisingSetCallback();
}
- void start(byte[] advertisementPackets, BroadcastListener listener) {
+ void start(@BroadcastRequest.BroadcastVersion int version, byte[] advertisementPackets,
+ BroadcastListener listener) {
if (mIsAdvertising) {
stop();
}
@@ -64,23 +74,36 @@
mInjector.getBluetoothAdapter().getBluetoothLeAdvertiser();
if (bluetoothLeAdvertiser != null) {
advertiseStarted = true;
- AdvertiseSettings settings =
- new AdvertiseSettings.Builder()
- .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
- .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
- .setConnectable(true)
- .build();
-
- // TODO(b/230538655) Use empty data until Presence V1 protocol is implemented.
AdvertiseData advertiseData =
new AdvertiseData.Builder()
.addServiceData(new ParcelUuid(PRESENCE_UUID),
advertisementPackets).build();
-
try {
mBroadcastListener = listener;
- bluetoothLeAdvertiser.startAdvertising(settings, advertiseData, this);
+ switch (version) {
+ case BroadcastRequest.PRESENCE_VERSION_V0:
+ bluetoothLeAdvertiser.startAdvertising(getAdvertiseSettings(),
+ advertiseData, this);
+ break;
+ case BroadcastRequest.PRESENCE_VERSION_V1:
+ if (adapter.isLeExtendedAdvertisingSupported()) {
+ bluetoothLeAdvertiser.startAdvertisingSet(
+ getAdvertisingSetParameters(),
+ advertiseData,
+ null, null, null, mAdvertisingSetCallback);
+ } else {
+ Log.w(TAG, "Failed to start advertising set because the chipset"
+ + " does not supports LE Extended Advertising feature.");
+ advertiseStarted = false;
+ }
+ break;
+ default:
+ Log.w(TAG, "Failed to start advertising set because the advertisement"
+ + " is wrong.");
+ advertiseStarted = false;
+ }
} catch (NullPointerException | IllegalStateException | SecurityException e) {
+ Log.w(TAG, "Failed to start advertising.", e);
advertiseStarted = false;
}
}
@@ -98,6 +121,7 @@
mInjector.getBluetoothAdapter().getBluetoothLeAdvertiser();
if (bluetoothLeAdvertiser != null) {
bluetoothLeAdvertiser.stopAdvertising(this);
+ bluetoothLeAdvertiser.stopAdvertisingSet(mAdvertisingSetCallback);
}
}
mBroadcastListener = null;
@@ -121,4 +145,40 @@
mBroadcastListener.onStatusChanged(BroadcastCallback.STATUS_FAILURE);
}
}
+
+ private static AdvertiseSettings getAdvertiseSettings() {
+ return new AdvertiseSettings.Builder()
+ .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
+ .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
+ .setConnectable(true)
+ .build();
+ }
+
+ private static AdvertisingSetParameters getAdvertisingSetParameters() {
+ return new AdvertisingSetParameters.Builder()
+ .setInterval(AdvertisingSetParameters.INTERVAL_MEDIUM)
+ .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_MEDIUM)
+ .setConnectable(true)
+ .build();
+ }
+
+ private AdvertisingSetCallback getAdvertisingSetCallback() {
+ return new AdvertisingSetCallback() {
+ @Override
+ public void onAdvertisingSetStarted(AdvertisingSet advertisingSet,
+ int txPower, int status) {
+ if (status == AdvertisingSetCallback.ADVERTISE_SUCCESS) {
+ if (mBroadcastListener != null) {
+ mBroadcastListener.onStatusChanged(BroadcastCallback.STATUS_OK);
+ }
+ mIsAdvertising = true;
+ } else {
+ Log.e(TAG, "Starts advertising failed in status " + status);
+ if (mBroadcastListener != null) {
+ mBroadcastListener.onStatusChanged(BroadcastCallback.STATUS_FAILURE);
+ }
+ }
+ }
+ };
+ }
}
diff --git a/nearby/service/java/com/android/server/nearby/provider/BroadcastProviderManager.java b/nearby/service/java/com/android/server/nearby/provider/BroadcastProviderManager.java
index f7d45e3..e8714c7 100644
--- a/nearby/service/java/com/android/server/nearby/provider/BroadcastProviderManager.java
+++ b/nearby/service/java/com/android/server/nearby/provider/BroadcastProviderManager.java
@@ -87,7 +87,8 @@
return;
}
mBroadcastListener = listener;
- mBleBroadcastProvider.start(advertisement.toBytes(), this);
+ mBleBroadcastProvider.start(presenceBroadcastRequest.getVersion(),
+ advertisement.toBytes(), this);
});
}
}
diff --git a/nearby/tests/unit/src/com/android/server/nearby/provider/BleBroadcastProviderTest.java b/nearby/tests/unit/src/com/android/server/nearby/provider/BleBroadcastProviderTest.java
index 88cd9af..20fdc93 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/provider/BleBroadcastProviderTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/provider/BleBroadcastProviderTest.java
@@ -16,6 +16,7 @@
package com.android.server.nearby.provider;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -24,8 +25,10 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.AdvertisingSetCallback;
import android.content.Context;
import android.nearby.BroadcastCallback;
+import android.nearby.BroadcastRequest;
import androidx.test.core.app.ApplicationProvider;
@@ -59,9 +62,10 @@
}
@Test
- public void testOnStatus_success() {
+ public void testOnStatus_success_fastAdv() {
byte[] advertiseBytes = new byte[]{1, 2, 3, 4};
- mBleBroadcastProvider.start(advertiseBytes, mBroadcastListener);
+ mBleBroadcastProvider.start(BroadcastRequest.PRESENCE_VERSION_V0,
+ advertiseBytes, mBroadcastListener);
AdvertiseSettings settings = new AdvertiseSettings.Builder().build();
mBleBroadcastProvider.onStartSuccess(settings);
@@ -69,9 +73,22 @@
}
@Test
- public void testOnStatus_failure() {
+ public void testOnStatus_success_extendedAdv() {
byte[] advertiseBytes = new byte[]{1, 2, 3, 4};
- mBleBroadcastProvider.start(advertiseBytes, mBroadcastListener);
+ mBleBroadcastProvider.start(BroadcastRequest.PRESENCE_VERSION_V1,
+ advertiseBytes, mBroadcastListener);
+
+ // advertising set can not be mocked, so we will allow nulls
+ mBleBroadcastProvider.mAdvertisingSetCallback.onAdvertisingSetStarted(null, -30,
+ AdvertisingSetCallback.ADVERTISE_SUCCESS);
+ verify(mBroadcastListener).onStatusChanged(eq(BroadcastCallback.STATUS_OK));
+ }
+
+ @Test
+ public void testOnStatus_failure_fastAdv() {
+ byte[] advertiseBytes = new byte[]{1, 2, 3, 4};
+ mBleBroadcastProvider.start(BroadcastRequest.PRESENCE_VERSION_V0,
+ advertiseBytes, mBroadcastListener);
mBleBroadcastProvider.onStartFailure(BroadcastCallback.STATUS_FAILURE);
verify(mBroadcastListener, times(1))
@@ -79,6 +96,20 @@
}
@Test
+ public void testOnStatus_failure_extendedAdv() {
+ byte[] advertiseBytes = new byte[]{1, 2, 3, 4};
+ mBleBroadcastProvider.start(BroadcastRequest.PRESENCE_VERSION_V1,
+ advertiseBytes, mBroadcastListener);
+
+ // advertising set can not be mocked, so we will allow nulls
+ mBleBroadcastProvider.mAdvertisingSetCallback.onAdvertisingSetStarted(null, -30,
+ AdvertisingSetCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
+ // Can be additional failure if the test device does not support LE Extended Advertising.
+ verify(mBroadcastListener, atLeastOnce())
+ .onStatusChanged(eq(BroadcastCallback.STATUS_FAILURE));
+ }
+
+ @Test
public void testStop() {
mBleBroadcastProvider.stop();
}
diff --git a/nearby/tests/unit/src/com/android/server/nearby/provider/BroadcastProviderManagerTest.java b/nearby/tests/unit/src/com/android/server/nearby/provider/BroadcastProviderManagerTest.java
index 5090cc0..0179901 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/provider/BroadcastProviderManagerTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/provider/BroadcastProviderManagerTest.java
@@ -101,8 +101,8 @@
@Test
public void testStartAdvertising() {
mBroadcastProviderManager.startBroadcast(mBroadcastRequest, mBroadcastListener);
- verify(mBleBroadcastProvider).start(any(byte[].class), any(
- BleBroadcastProvider.BroadcastListener.class));
+ verify(mBleBroadcastProvider).start(eq(BroadcastRequest.PRESENCE_VERSION_V0),
+ any(byte[].class), any(BleBroadcastProvider.BroadcastListener.class));
}
@Test