diff options
author | Googler <noreply@google.com> | 2024-04-23 11:13:29 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2024-04-23 11:14:04 -0700 |
commit | 811b0ff8c67bdd29997126bf7a09916e26ab5303 (patch) | |
tree | f54b7d631a46fa3f64fba0e2ef4af4094dbadf17 | |
parent | 6131a9b624eb61aba41896dbf3b26f67c182ab31 (diff) | |
download | robolectric-811b0ff8c67bdd29997126bf7a09916e26ab5303.tar.gz |
Add #startAdvertisingSet API support in ShadowBluetoothLeAdvertiser.
Extends ShadowBluetoothLeAdvertiser minSdk from O to L.
PiperOrigin-RevId: 627447267
2 files changed, 324 insertions, 196 deletions
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothLeAdvertiserTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothLeAdvertiserTest.java index 7dc4fe798..9b2ffb50b 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothLeAdvertiserTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothLeAdvertiserTest.java @@ -1,15 +1,13 @@ package org.robolectric.shadows; +import static android.os.Build.VERSION_CODES.LOLLIPOP; import static android.os.Build.VERSION_CODES.O; -import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import static org.robolectric.Shadows.shadowOf; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGattServer; -import android.bluetooth.BluetoothManager; import android.bluetooth.le.AdvertiseCallback; import android.bluetooth.le.AdvertiseData; import android.bluetooth.le.AdvertiseSettings; @@ -18,11 +16,9 @@ import android.bluetooth.le.AdvertisingSetCallback; import android.bluetooth.le.AdvertisingSetParameters; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.PeriodicAdvertisingParameters; -import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.ParcelUuid; -import androidx.test.core.app.ApplicationProvider; import java.util.Optional; import org.junit.Before; import org.junit.Test; @@ -32,7 +28,7 @@ import org.robolectric.annotation.Config; /** Unit tests for {@link ShadowBluetoothLeAdvertiser}. */ @RunWith(RobolectricTestRunner.class) -@Config(minSdk = O) +@Config(minSdk = LOLLIPOP) public class ShadowBluetoothLeAdvertiserTest { private static final String ADVERTISE_DATA_UUID1 = "00000000-0000-0000-0000-0000000000A1"; @@ -43,13 +39,6 @@ public class ShadowBluetoothLeAdvertiserTest { private static final String CALLBACK1_FAILURE_RESULT = "c1f"; private static final String CALLBACK2_SUCCESS_RESULT = "c2s"; private static final String CALLBACK2_FAILURE_RESULT = "c2f"; - - private final Context context = ApplicationProvider.getApplicationContext(); - private final BluetoothManager bluetoothManager = - context.getSystemService(BluetoothManager.class); - private final BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter(); - private final ShadowBluetoothAdapter shadowBluetoothAdapter = shadowOf(bluetoothAdapter); - private final BluetoothGattServer gattServer = bluetoothManager.openGattServer(context, null); private final Handler mainLooperHandler = new Handler(Looper.getMainLooper()); private BluetoothLeAdvertiser bluetoothLeAdvertiser; @@ -62,33 +51,6 @@ public class ShadowBluetoothLeAdvertiserTest { private AdvertiseData scanResponse2; private AdvertiseCallback advertiseCallback1; private AdvertiseCallback advertiseCallback2; - - private Optional<Integer> advertisingSetStartStatusOptional; - private boolean advertisingSetStopped; - private AdvertisingSetCallback advertisingSetCallback = - new AdvertisingSetCallback() { - @Override - public void onAdvertisingSetStarted( - AdvertisingSet advertisingSet, int txPower, int status) { - advertisingSetStartStatusOptional = Optional.of(status); - /* switch (status) { - case AdvertisingSetCallback.ADVERTISE_SUCCESS: - advertisingSetStartStatusOptional. - break; - case AdvertisingSetCallback.ADVERTISE_FAILED_DATA_TOO_LARGE: - break; - case AdvertisingSetCallback.ADVERTISE_FAILED_ALREADY_STARTED: - break; - default: - break; */ - } - - @Override - public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) { - advertisingSetStopped = true; - } - }; - private String result; private int error; private AdvertiseSettings settings; @@ -170,9 +132,6 @@ public class ShadowBluetoothLeAdvertiserTest { .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_LOW) .setConnectable(false) .build(); - - advertisingSetStartStatusOptional = Optional.empty(); - advertisingSetStopped = false; } @Test @@ -246,10 +205,10 @@ public class ShadowBluetoothLeAdvertiserTest { .addServiceUuid(ParcelUuid.fromString("EEEEEEEE-FFFF-FFFF-FFFF-FFFFFFFFFFFF")) .build(); bluetoothLeAdvertiser.startAdvertising( - advertiseSettings1, null, oversizedData, advertiseCallback1); + advertiseSettings1, /* advertiseData= */ null, oversizedData, advertiseCallback1); assertThat(error).isEqualTo(AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); bluetoothLeAdvertiser.startAdvertising( - advertiseSettings1, oversizedData, null, advertiseCallback1); + advertiseSettings1, oversizedData, /* scanResponse= */ null, advertiseCallback1); assertThat(error).isEqualTo(AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); } @@ -502,84 +461,86 @@ public class ShadowBluetoothLeAdvertiserTest { } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void startAdvertisingSet() { + AdvertisingStatus status = new AdvertisingStatus(); bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - true, true, true, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ true, + /* isConnectable= */ true, + /* isScannable= */ true, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_CODED), advertiseData1, - null, - null, - null, - 0, - 0, - gattServer, - advertisingSetCallback, - mainLooperHandler); - - assertThat(advertisingSetStartStatusOptional.get()) - .isEqualTo(AdvertisingSetCallback.ADVERTISE_SUCCESS); + /* scanResponse= */ null, + /* periodicParameters= */ null, + /* periodicData= */ null, + createAdvertisingSetCallback(status)); + + assertThat(status.isStarted).isTrue(); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(1); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void startAdvertisingSet_advertisingAlreadyStarted_invokeOnAdvertisingSetStartedWithAlreadyStartedStatusCode() { + AdvertisingStatus status = new AdvertisingStatus(); + AdvertisingSetCallback callback = createAdvertisingSetCallback(status); bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - true, true, true, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ true, + /* isConnectable= */ true, + /* isScannable= */ true, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_CODED), advertiseData1, - null, - null, - null, - 0, - 0, - gattServer, - advertisingSetCallback, - mainLooperHandler); + /* scanResponse= */ null, + /* periodicParameters= */ null, + /* periodicData= */ null, + callback); bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - true, true, true, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ true, + /* isConnectable= */ true, + /* isScannable= */ true, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_CODED), advertiseData1, - null, - null, - null, - 0, - 0, - gattServer, - advertisingSetCallback, - mainLooperHandler); - - assertThat(advertisingSetStartStatusOptional.get()) + /* scanResponse= */ null, + /* periodicParameters= */ null, + /* periodicData= */ null, + callback); + + assertThat(status.getStatusCode()) .isEqualTo(AdvertisingSetCallback.ADVERTISE_FAILED_ALREADY_STARTED); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(1); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void startAdvertisingSet_nullCallback_throwsIllegalArgumentException() { assertThrows( IllegalArgumentException.class, () -> bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - true, true, true, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ true, + /* isConnectable= */ true, + /* isScannable= */ true, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_CODED), advertiseData1, - null, - null, - null, - 0, - 0, - gattServer, - null, - mainLooperHandler)); + /* scanResponse= */ null, + /* periodicParameters= */ null, + /* periodicData= */ null, + /* callback= */ null)); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(0); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void startAdvertisingSet_legacyModeWithTooBigAdvertiseData_throwsIllegalArgumentException() { AdvertiseData oversizedData = @@ -593,21 +554,22 @@ public class ShadowBluetoothLeAdvertiserTest { () -> bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - true, true, true, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ true, + /* isConnectable= */ true, + /* isScannable= */ true, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_CODED), oversizedData, /* scanResponse= */ null, /* periodicParameters= */ null, /* periodicData= */ null, - /* duration= */ 0, - /* maxExtendedAdvertisingEvents= */ 0, - gattServer, - advertisingSetCallback, + createAdvertisingSetCallback(), mainLooperHandler)); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(0); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void startAdvertisingSet_legacyModeWithTooBigScanResponse_throwsIllegalArgumentException() { AdvertiseData oversizedData = @@ -621,72 +583,72 @@ public class ShadowBluetoothLeAdvertiserTest { () -> bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - true, true, true, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ true, + /* isConnectable= */ true, + /* isScannable= */ true, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_CODED), advertiseData1, oversizedData, /* periodicParameters= */ null, /* periodicData= */ null, - /* duration= */ 0, - /* maxExtendedAdvertisingEvents= */ 0, - gattServer, - advertisingSetCallback, - mainLooperHandler)); + createAdvertisingSetCallback())); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(0); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void startAdvertisingSet_nonLegacyModePrimaryPhySetButNotSupported_throwsIllegalArgumentException() { - shadowBluetoothAdapter.setIsLeCodedPhySupported(false); + shadowOf(BluetoothAdapter.getDefaultAdapter()).setIsLeCodedPhySupported(false); assertThrows( IllegalArgumentException.class, () -> bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - false, true, false, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_1M), + /* isLegacy= */ false, + /* isConnectable= */ true, + /* isScannable= */ false, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_1M), advertiseData1, /* scanResponse= */ null, /* periodicParameters= */ null, /* periodicData= */ null, - /* duration= */ 0, - /* maxExtendedAdvertisingEvents= */ 0, - gattServer, - advertisingSetCallback, - mainLooperHandler)); + createAdvertisingSetCallback())); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(0); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void startAdvertisingSet_nonLegacyModeSecondaryPhySetButNotSupported_throwsIllegalArgumentException() { - shadowBluetoothAdapter.setIsLeCodedPhySupported(false); + shadowOf(BluetoothAdapter.getDefaultAdapter()).setIsLeCodedPhySupported(false); assertThrows( IllegalArgumentException.class, () -> bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - false, true, false, BluetoothDevice.PHY_LE_1M, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ false, + /* isConnectable= */ true, + /* isScannable= */ false, + BluetoothDevice.PHY_LE_1M, + BluetoothDevice.PHY_LE_CODED), advertiseData1, /* scanResponse= */ null, /* periodicParameters= */ null, /* periodicData= */ null, - /* duration= */ 0, - /* maxExtendedAdvertisingEvents= */ 0, - gattServer, - advertisingSetCallback, - mainLooperHandler)); + createAdvertisingSetCallback())); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(0); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void startAdvertisingSet_nonLegacyModeWithTooBigAdvertiseData_throwsIllegalArgumentException() { - shadowBluetoothAdapter.setIsLeExtendedAdvertisingSupported(false); + shadowOf(BluetoothAdapter.getDefaultAdapter()).setIsLeExtendedAdvertisingSupported(false); AdvertiseData oversizedData = new AdvertiseData.Builder() .addServiceUuid(ParcelUuid.fromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")) @@ -698,24 +660,24 @@ public class ShadowBluetoothLeAdvertiserTest { () -> bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - false, true, false, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ false, + /* isConnectable= */ true, + /* isScannable= */ false, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_CODED), oversizedData, /* scanResponse= */ null, /* periodicParameters= */ null, /* periodicData= */ null, - /* duration= */ 0, - /* maxExtendedAdvertisingEvents= */ 0, - gattServer, - advertisingSetCallback, - mainLooperHandler)); + createAdvertisingSetCallback())); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(0); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void startAdvertisingSet_nonLegacyModeWithTooBigScanResponse_throwsIllegalArgumentException() { - shadowBluetoothAdapter.setIsLeExtendedAdvertisingSupported(false); + shadowOf(BluetoothAdapter.getDefaultAdapter()).setIsLeExtendedAdvertisingSupported(false); AdvertiseData oversizedData = new AdvertiseData.Builder() .addServiceUuid(ParcelUuid.fromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")) @@ -727,24 +689,24 @@ public class ShadowBluetoothLeAdvertiserTest { () -> bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - false, true, false, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ false, + /* isConnectable= */ true, + /* isScannable= */ false, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_CODED), advertiseData1, oversizedData, /* periodicParameters= */ null, /* periodicData= */ null, - /* duration= */ 0, - /* maxExtendedAdvertisingEvents= */ 0, - gattServer, - advertisingSetCallback, - mainLooperHandler)); + createAdvertisingSetCallback())); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(0); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void startAdvertisingSet_nonLegacyModeWithTooBigPeriodicData_throwsIllegalArgumentException() { - shadowBluetoothAdapter.setIsLeExtendedAdvertisingSupported(false); + shadowOf(BluetoothAdapter.getDefaultAdapter()).setIsLeExtendedAdvertisingSupported(false); AdvertiseData oversizedData = new AdvertiseData.Builder() .addServiceUuid(ParcelUuid.fromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")) @@ -756,21 +718,21 @@ public class ShadowBluetoothLeAdvertiserTest { () -> bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - false, true, false, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ false, + /* isConnectable= */ true, + /* isScannable= */ false, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_CODED), advertiseData1, /* scanResponse= */ null, new PeriodicAdvertisingParameters.Builder().setInterval(1).build(), oversizedData, - /* duration= */ 0, - /* maxExtendedAdvertisingEvents= */ 0, - gattServer, - advertisingSetCallback, - mainLooperHandler)); + createAdvertisingSetCallback())); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(0); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void startAdvertisingSet_maxExtendedAdvertisingEventsOutOfRange_throwsIllegalArgumentException() { assertThrows( @@ -778,65 +740,73 @@ public class ShadowBluetoothLeAdvertiserTest { () -> bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - false, true, false, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ false, + /* isConnectable= */ true, + /* isScannable= */ false, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_CODED), advertiseData1, /* scanResponse= */ null, /* periodicParameters= */ null, /* periodicData= */ null, /* duration= */ 0, - -1, - gattServer, - advertisingSetCallback, + /* maxExtendedAdvertisingEvents= */ -1, + createAdvertisingSetCallback(), mainLooperHandler)); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(0); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void startAdvertisingSet_durationOutOfRange_throwsIllegalArgumentException() { assertThrows( IllegalArgumentException.class, () -> bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - false, true, false, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ false, + /* isConnectable= */ true, + /* isScannable= */ false, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_CODED), advertiseData1, /* scanResponse= */ null, /* periodicParameters= */ null, /* periodicData= */ null, - -1, + /* duration= */ -1, /* maxExtendedAdvertisingEvents= */ 0, - gattServer, - advertisingSetCallback, - mainLooperHandler)); + createAdvertisingSetCallback())); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(0); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void stopAdvertisingSet() { + AdvertisingStatus status = new AdvertisingStatus(); + AdvertisingSetCallback callback = createAdvertisingSetCallback(status); bluetoothLeAdvertiser.startAdvertisingSet( buildAdvertisingSetParams( - true, true, true, BluetoothDevice.PHY_LE_CODED, BluetoothDevice.PHY_LE_CODED), + /* isLegacy= */ true, + /* isConnectable= */ true, + /* isScannable= */ true, + BluetoothDevice.PHY_LE_CODED, + BluetoothDevice.PHY_LE_CODED), advertiseData1, - null, - null, - null, - 0, - 0, - gattServer, - advertisingSetCallback, - mainLooperHandler); + /* scanResponse= */ null, + /* periodicParameters= */ null, + /* periodicData= */ null, + callback); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(1); + assertThat(status.isStarted).isTrue(); - bluetoothLeAdvertiser.stopAdvertisingSet(advertisingSetCallback); + bluetoothLeAdvertiser.stopAdvertisingSet(callback); - assertThat(advertisingSetStopped).isTrue(); + assertThat(status.isStarted).isFalse(); assertThat(shadowOf(bluetoothLeAdvertiser).getAdvertisingSetRequestCount()).isEqualTo(0); } @Test - @Config(minSdk = UPSIDE_DOWN_CAKE) + @Config(minSdk = O) public void stopAdvertisingSet_nullCallback_throwsIllegalArgumentException() { assertThrows( IllegalArgumentException.class, () -> bluetoothLeAdvertiser.stopAdvertisingSet(null)); @@ -856,4 +826,51 @@ public class ShadowBluetoothLeAdvertiserTest { .setSecondaryPhy(secondaryPhy) .build(); } + + private AdvertisingSetCallback createAdvertisingSetCallback() { + return createAdvertisingSetCallback(new AdvertisingStatus()); + } + + private AdvertisingSetCallback createAdvertisingSetCallback(AdvertisingStatus advertisingStatus) { + return new AdvertisingSetCallback() { + @Override + public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) { + advertisingStatus.setStatusCode(status); + if (status == AdvertisingSetCallback.ADVERTISE_SUCCESS) { + advertisingStatus.setStarted(true); + } + } + + @Override + public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) { + advertisingStatus.setStarted(false); + } + }; + } + + static class AdvertisingStatus { + private Optional<Integer> statusCode; + private boolean isStarted; + + AdvertisingStatus() { + isStarted = false; + statusCode = Optional.empty(); + } + + public void setStatusCode(int statusCode) { + this.statusCode = Optional.of(statusCode); + } + + public void setStarted(boolean started) { + this.isStarted = started; + } + + public int getStatusCode() { + return statusCode.get(); + } + + public boolean isStarted() { + return isStarted; + } + } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothLeAdvertiser.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothLeAdvertiser.java index c4e614dd5..ae8d16d46 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothLeAdvertiser.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothLeAdvertiser.java @@ -1,5 +1,6 @@ package org.robolectric.shadows; +import static android.os.Build.VERSION_CODES.LOLLIPOP; import static android.os.Build.VERSION_CODES.O; import static android.os.Build.VERSION_CODES.R; import static android.os.Build.VERSION_CODES.S; @@ -19,7 +20,10 @@ import android.bluetooth.le.AdvertisingSetParameters; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.PeriodicAdvertisingParameters; import android.content.AttributionSource; +import android.os.Build; +import android.os.Build.VERSION_CODES; import android.os.Handler; +import android.os.Looper; import android.os.ParcelUuid; import java.util.HashMap; import java.util.HashSet; @@ -36,7 +40,7 @@ import org.robolectric.util.reflector.Direct; import org.robolectric.util.reflector.ForType; /** Shadow implementation of {@link BluetoothLeAdvertiser}. */ -@Implements(value = BluetoothLeAdvertiser.class, minSdk = O) +@Implements(value = BluetoothLeAdvertiser.class, minSdk = LOLLIPOP) public class ShadowBluetoothLeAdvertiser { private static final String CALLBACK_NULL_MESSAGE = "callback cannot be null."; @@ -135,23 +139,116 @@ public class ShadowBluetoothLeAdvertiser { } /** - * Start Bluetooth LE Advertising Set. This method returns immediately, the operation status is - * delivered through {@code callback}. - * - * @param parameters Advertising set parameters. - * @param advertiseData Advertisement data to be broadcasted. - * @param scanResponse Scan response associated with the advertisement data. - * @param periodicParameters Periodic advertisng parameters. - * @param periodicData Periodic advertising data. - * @param duration Advertising duration, in 10ms unit. - * @param maxExtendedAdvertisingEvents Maximum number of extended advertising events the - * controller shall attempt to send prior to terminating the extended advertising, even if the - * duration has not expired. - * @param gattServer GattServer the GATT server that will "own" connections derived from this - * advertising. - * @param callback Callback for advertising set. - * @param handler Thread upon which the callbacks will be invoked. - * @throws IllegalArgumentException When {@code callback} is not present. + * Creates a new advertising set. If operation succeed, device will start advertising. This method + * returns immediately, the operation status is delivered through {@code + * callback.onAdvertisingSetStarted()} on the caller thread. + */ + @Implementation(minSdk = O) + protected void startAdvertisingSet( + AdvertisingSetParameters parameters, + AdvertiseData advertiseData, + AdvertiseData scanResponse, + PeriodicAdvertisingParameters periodicParameters, + AdvertiseData periodicData, + AdvertisingSetCallback callback) { + startAdvertisingSet( + parameters, + advertiseData, + scanResponse, + periodicParameters, + periodicData, + /* duration= */ 0, + /* maxExtendedAdvertisingEvents= */ 0, + callback, + new Handler(Looper.getMainLooper())); + } + + /** + * Creates a new advertising set. If operation succeed, device will start advertising. This method + * returns immediately, the operation status is delivered through {@code + * callback.onAdvertisingSetStarted()} on the caller thread instead of the {@code handler}. + */ + @Implementation(minSdk = O) + protected void startAdvertisingSet( + AdvertisingSetParameters parameters, + AdvertiseData advertiseData, + AdvertiseData scanResponse, + PeriodicAdvertisingParameters periodicParameters, + AdvertiseData periodicData, + AdvertisingSetCallback callback, + Handler handler) { + startAdvertisingSet( + parameters, + advertiseData, + scanResponse, + periodicParameters, + periodicData, + /* duration= */ 0, + /* maxExtendedAdvertisingEvents= */ 0, + callback, + handler); + } + + /** + * Creates a new advertising set. If operation succeed, device will start advertising. This method + * returns immediately, the operation status is delivered through {@code + * callback.onAdvertisingSetStarted()} on the caller thread. + */ + @Implementation(minSdk = O) + protected void startAdvertisingSet( + AdvertisingSetParameters parameters, + AdvertiseData advertiseData, + AdvertiseData scanResponse, + PeriodicAdvertisingParameters periodicParameters, + AdvertiseData periodicData, + int duration, + int maxExtendedAdvertisingEvents, + AdvertisingSetCallback callback) { + startAdvertisingSet( + parameters, + advertiseData, + scanResponse, + periodicParameters, + periodicData, + duration, + maxExtendedAdvertisingEvents, + callback, + new Handler(Looper.getMainLooper())); + } + + /** + * Creates a new advertising set. If operation succeed, device will start advertising. This method + * returns immediately, the operation status is delivered through {@code + * callback.onAdvertisingSetStarted()} on the caller thread instead of the {@code handler}. + */ + @Implementation(minSdk = O) + protected void startAdvertisingSet( + AdvertisingSetParameters parameters, + AdvertiseData advertiseData, + AdvertiseData scanResponse, + PeriodicAdvertisingParameters periodicParameters, + AdvertiseData periodicData, + int duration, + int maxExtendedAdvertisingEvents, + AdvertisingSetCallback callback, + Handler handler) { + startAdvertisingSet( + parameters, + advertiseData, + scanResponse, + periodicParameters, + periodicData, + duration, + maxExtendedAdvertisingEvents, + /* gattServer= */ null, + callback, + handler); + } + + /** + * Creates a new advertising set. If operation succeed, device will start advertising. This method + * returns immediately, the operation status is delivered through {@code + * callback.onAdvertisingSetStarted()} on the caller thread instead of the {@code handler}. */ @Implementation(minSdk = UPSIDE_DOWN_CAKE) protected void startAdvertisingSet( @@ -170,7 +267,10 @@ public class ShadowBluetoothLeAdvertiser { } boolean isConnectable = parameters.isConnectable(); - boolean isDiscoverable = parameters.isDiscoverable(); + boolean isDiscoverable = true; + if (Build.VERSION.SDK_INT >= UPSIDE_DOWN_CAKE) { + isDiscoverable = parameters.isDiscoverable(); + } boolean hasFlags = isConnectable && isDiscoverable; if (parameters.isLegacy()) { if (getTotalBytes(advertiseData, hasFlags) > MAX_LEGACY_ADVERTISING_DATA_BYTES) { @@ -231,16 +331,27 @@ public class ShadowBluetoothLeAdvertiser { return; } - AdvertisingSet advertisingSet = - ReflectionHelpers.callConstructor( - AdvertisingSet.class, - ClassParameter.from(int.class, advertiserId.getAndAdd(1)), - ClassParameter.from( - IBluetoothManager.class, - ReflectionHelpers.createNullProxy(IBluetoothManager.class)), - ClassParameter.from( - AttributionSource.class, - ReflectionHelpers.callInstanceMethod(bluetoothAdapter, "getAttributionSource"))); + AdvertisingSet advertisingSet; + if (Build.VERSION.SDK_INT >= VERSION_CODES.S) { + advertisingSet = + ReflectionHelpers.callConstructor( + AdvertisingSet.class, + ClassParameter.from(int.class, advertiserId.getAndAdd(1)), + ClassParameter.from( + IBluetoothManager.class, + ReflectionHelpers.createNullProxy(IBluetoothManager.class)), + ClassParameter.from( + AttributionSource.class, + ReflectionHelpers.callInstanceMethod(bluetoothAdapter, "getAttributionSource"))); + } else { + advertisingSet = + ReflectionHelpers.callConstructor( + AdvertisingSet.class, + ClassParameter.from(int.class, advertiserId.getAndAdd(1)), + ClassParameter.from( + IBluetoothManager.class, + ReflectionHelpers.createNullProxy(IBluetoothManager.class))); + } callback.onAdvertisingSetStarted( advertisingSet, parameters.getTxPowerLevel(), AdvertisingSetCallback.ADVERTISE_SUCCESS); @@ -255,7 +366,7 @@ public class ShadowBluetoothLeAdvertiser { * @param callback Callback for advertising set. * @throws IllegalArgumentException When {@code callback} is not present. */ - @Implementation(minSdk = UPSIDE_DOWN_CAKE) + @Implementation(minSdk = O) protected void stopAdvertisingSet(AdvertisingSetCallback callback) { if (callback == null) { throw new IllegalArgumentException("callback cannot be null"); |