Skip to content

Commit

Permalink
Update ShadowBluetoothDevice to throw an exception if the BLUETOOTH_C…
Browse files Browse the repository at this point in the history
…ONNECT permission isn't granted.

PiperOrigin-RevId: 433004311
  • Loading branch information
Googler authored and hoisie committed Mar 16, 2022
1 parent 41012c1 commit 31b77be
Show file tree
Hide file tree
Showing 2 changed files with 246 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.robolectric.shadows;

import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.bluetooth.BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES;
import static android.bluetooth.BluetoothDevice.BOND_BONDED;
import static android.bluetooth.BluetoothDevice.BOND_NONE;
Expand All @@ -9,16 +10,19 @@
import static android.os.Build.VERSION_CODES.O;
import static android.os.Build.VERSION_CODES.Q;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.robolectric.Shadows.shadowOf;

import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothSocket;
import android.os.Build.VERSION_CODES;
import android.os.Handler;
import android.os.ParcelUuid;
import androidx.test.core.app.ApplicationProvider;
Expand All @@ -35,6 +39,7 @@
public class ShadowBluetoothDeviceTest {

private static final String MOCK_MAC_ADDRESS = "00:11:22:33:AA:BB";
private final Application application = ApplicationProvider.getApplicationContext();

@Test
public void canCreateBluetoothDeviceViaNewInstance() throws Exception {
Expand All @@ -46,6 +51,7 @@ public void canCreateBluetoothDeviceViaNewInstance() throws Exception {

@Test
public void canSetAndGetUuids() throws Exception {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(MOCK_MAC_ADDRESS);
ParcelUuid[] uuids =
new ParcelUuid[] {
Expand All @@ -59,12 +65,14 @@ public void canSetAndGetUuids() throws Exception {

@Test
public void getUuids_setUuidsNotCalled_shouldReturnNull() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(MOCK_MAC_ADDRESS);
assertThat(device.getUuids()).isNull();
}

@Test
public void canSetAndGetBondState() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(MOCK_MAC_ADDRESS);

assertThat(device.getBondState()).isEqualTo(BOND_NONE);
Expand All @@ -75,6 +83,7 @@ public void canSetAndGetBondState() {

@Test
public void canSetAndGetCreatedBond() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(MOCK_MAC_ADDRESS);

assertThat(device.createBond()).isFalse();
Expand All @@ -85,6 +94,7 @@ public void canSetAndGetCreatedBond() {

@Test
public void canSetAndGetPin() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(MOCK_MAC_ADDRESS);

assertThat(shadowOf(device).getPin()).isNull();
Expand All @@ -109,6 +119,7 @@ public void canSetAndGetPairingConfirmation() {

@Test
public void canSetAndGetFetchUuidsWithSdpResult() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(MOCK_MAC_ADDRESS);
assertThat(device.fetchUuidsWithSdp()).isFalse();

Expand All @@ -118,6 +129,7 @@ public void canSetAndGetFetchUuidsWithSdpResult() {

@Test
public void canSetAndGetBluetoothClass() throws Exception {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(MOCK_MAC_ADDRESS);

assertThat(shadowOf(device).getBluetoothClass()).isNull();
Expand All @@ -130,6 +142,7 @@ public void canSetAndGetBluetoothClass() throws Exception {

@Test
public void canCreateAndRemoveBonds() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(MOCK_MAC_ADDRESS);

assertThat(device.createBond()).isFalse();
Expand All @@ -142,6 +155,7 @@ public void canCreateAndRemoveBonds() {

@Test
public void getCorrectFetchUuidsWithSdpCount() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(MOCK_MAC_ADDRESS);
assertThat(shadowOf(device).getFetchUuidsWithSdpCount()).isEqualTo(0);

Expand All @@ -155,6 +169,7 @@ public void getCorrectFetchUuidsWithSdpCount() {
@Test
@Config(minSdk = JELLY_BEAN_MR2)
public void connectGatt_doesntCrash() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice bluetoothDevice = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
assertThat(
bluetoothDevice.connectGatt(
Expand All @@ -165,6 +180,7 @@ public void connectGatt_doesntCrash() {
@Test
@Config(minSdk = M)
public void connectGatt_withTransport_doesntCrash() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice bluetoothDevice = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
assertThat(
bluetoothDevice.connectGatt(
Expand Down Expand Up @@ -207,6 +223,7 @@ public void connectGatt_withTransportPhyHandler_doesntCrash() {
@Test
@Config(minSdk = JELLY_BEAN_MR2)
public void canSetAndGetType() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(MOCK_MAC_ADDRESS);

shadowOf(device).setType(DEVICE_TYPE_CLASSIC);
Expand All @@ -216,6 +233,7 @@ public void canSetAndGetType() {
@Test
@Config(minSdk = JELLY_BEAN_MR2)
public void canGetBluetoothGatts() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
List<BluetoothGatt> createdGatts = new ArrayList<>();

Expand All @@ -232,6 +250,7 @@ public void canGetBluetoothGatts() {
@Test
@Config(minSdk = JELLY_BEAN_MR2)
public void connectGatt_setsBluetoothGattCallback() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
BluetoothGattCallback callback = new BluetoothGattCallback() {};

Expand All @@ -245,6 +264,7 @@ public void connectGatt_setsBluetoothGattCallback() {
@Test
@Config(minSdk = JELLY_BEAN_MR2)
public void canSimulateGattConnectionChange() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
BluetoothGattCallback callback = mock(BluetoothGattCallback.class);
BluetoothGatt bluetoothGatt =
Expand All @@ -266,6 +286,7 @@ public void createRfcommSocketToServiceRecord_returnsSocket() throws Exception {
}

@Test
@Config(maxSdk = VERSION_CODES.R)
public void getSetAlias() {
String aliasName = "alias";
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
Expand All @@ -280,8 +301,8 @@ public void getSetAlias() {
}
}

@Config(maxSdk = Q)
@Test
@Config(maxSdk = Q)
public void getAliasName() {
String aliasName = "alias";
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
Expand All @@ -296,8 +317,159 @@ public void getAliasName() {
}
}

@Config(maxSdk = Q)
@Test
@Config(minSdk = VERSION_CODES.S)
public void getAliasName_noBluetoothConnectPermission_throwsException() {
shadowOf(application).denyPermissions(BLUETOOTH_CONNECT);
String aliasName = "alias";
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setAlias(aliasName);
shadowDevice.setShouldThrowSecurityExceptions(true);

assertThrows(SecurityException.class, device::getAlias);
}

@Test
@Config(minSdk = VERSION_CODES.S)
public void getUuids_noBluetoothConnectPermission_throwsException() {
shadowOf(application).denyPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setShouldThrowSecurityExceptions(true);

assertThrows(SecurityException.class, device::getUuids);
}

@Test
@Config(minSdk = VERSION_CODES.S)
public void getName_noBluetoothConnectPermission_throwsException() {
shadowOf(application).denyPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setShouldThrowSecurityExceptions(true);

assertThrows(SecurityException.class, device::getName);
}

@Test
@Config(minSdk = VERSION_CODES.S)
public void getType_noBluetoothConnectPermission_throwsException() {
shadowOf(application).denyPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setShouldThrowSecurityExceptions(true);

assertThrows(SecurityException.class, device::getType);
}

@Test
@Config(minSdk = VERSION_CODES.S)
public void fetchUuidsWithSdp_noBluetoothConnectPermission_throwsException() {
shadowOf(application).denyPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setShouldThrowSecurityExceptions(true);

assertThrows(SecurityException.class, device::fetchUuidsWithSdp);
}

@Test
@Config(minSdk = VERSION_CODES.S)
public void getBluetoothClass_noBluetoothConnectPermission_throwsException() {
shadowOf(application).denyPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setShouldThrowSecurityExceptions(true);

assertThrows(SecurityException.class, device::getBluetoothClass);
}

@Test
@Config(minSdk = VERSION_CODES.S)
public void getBondState_noBluetoothConnectPermission_throwsException() {
shadowOf(application).denyPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setShouldThrowSecurityExceptions(true);

assertThrows(SecurityException.class, device::getBondState);
}

@Test
@Config(minSdk = VERSION_CODES.S)
public void getPin_noBluetoothConnectPermission_throwsException() {
shadowOf(application).denyPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setShouldThrowSecurityExceptions(true);

byte[] pin = new byte[] {};
assertThrows(SecurityException.class, () -> device.setPin(pin));
}

@Test
@Config(minSdk = VERSION_CODES.S)
public void createBond_noBluetoothConnectPermission_throwsException() {
shadowOf(application).denyPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setShouldThrowSecurityExceptions(true);

assertThrows(SecurityException.class, device::createBond);
}

@Test
@Config(minSdk = VERSION_CODES.S)
public void createInsecureL2capChannel_noBluetoothConnectPermission_throwsException() {
shadowOf(application).denyPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setShouldThrowSecurityExceptions(true);

assertThrows(SecurityException.class, () -> device.createInsecureL2capChannel(0));
}

@Test
@Config(minSdk = VERSION_CODES.S)
public void createL2capChannel_noBluetoothConnectPermission_throwsException() {
shadowOf(application).denyPermissions(BLUETOOTH_CONNECT);
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setShouldThrowSecurityExceptions(true);

assertThrows(SecurityException.class, () -> device.createL2capChannel(0));
}

@Test
public void getAliasName_hasPermission_noExceptionThrown() {
shadowOf(application).grantPermissions(BLUETOOTH_CONNECT);
String aliasName = "alias";
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setAlias(aliasName);
shadowDevice.setShouldThrowSecurityExceptions(true);

String retrievedAlias = device.getAlias();
assertThat(retrievedAlias).isNotNull();
}

@Test
public void
getAliasName_noBluetoothConnectPermission_shouldThrowSecurityExceptionsFalse_noExceptionThrown() {
shadowOf(application).denyPermissions(BLUETOOTH_CONNECT);
String aliasName = "alias";
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
ShadowBluetoothDevice shadowDevice = shadowOf(device);
shadowDevice.setAlias(aliasName);
shadowDevice.setShouldThrowSecurityExceptions(false);

String retrievedAlias = device.getAlias();
assertThat(retrievedAlias).isNotNull();
}

@Test
@Config(maxSdk = Q)
public void getAliasName_aliasNull() {
String deviceName = "device name";
BluetoothDevice device = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS);
Expand Down

0 comments on commit 31b77be

Please sign in to comment.