[Pair hearing devices] Extract common behavior in BluetoothPairingDetail into Base class
* Before adding new hearing device feature, we will extract the common part into Base class first. They will share most of the UI component.
Bug: 237625815
Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothDevicePairingDetailBaseTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothDevicePairingDetailTest
Change-Id: I3a44c4c464d630fdcafa151afc82d3000fd728a3
diff --git a/res/xml/bluetooth_pairing_detail.xml b/res/xml/bluetooth_pairing_detail.xml
index 86fb9e4..460a708 100644
--- a/res/xml/bluetooth_pairing_detail.xml
+++ b/res/xml/bluetooth_pairing_detail.xml
@@ -27,7 +27,7 @@
<com.android.settings.bluetooth.BluetoothProgressCategory
android:key="available_devices"
- android:title="@string/bluetooth_paired_device_title"/>
+ android:title="@string/bluetooth_preference_found_media_devices"/>
<com.android.settingslib.widget.FooterPreference/>
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java b/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
new file mode 100644
index 0000000..c71decb
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
@@ -0,0 +1,200 @@
+/*
+ * 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 com.android.settings.bluetooth;
+
+import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilityStatsLogUtils;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.HearingAidStatsLogUtils;
+
+/**
+ * Abstract class for providing basic interaction for a list of Bluetooth devices in bluetooth
+ * device pairing detail page.
+ */
+public abstract class BluetoothDevicePairingDetailBase extends DeviceListPreferenceFragment {
+
+ protected boolean mInitialScanStarted;
+ @VisibleForTesting
+ protected BluetoothProgressCategory mAvailableDevicesCategory;
+
+ public BluetoothDevicePairingDetailBase() {
+ super(DISALLOW_CONFIG_BLUETOOTH);
+ }
+
+ @Override
+ public void initPreferencesFromPreferenceScreen() {
+ mAvailableDevicesCategory = findPreference(getDeviceListKey());
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ mInitialScanStarted = false;
+ super.onViewCreated(view, savedInstanceState);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ if (mLocalManager == null) {
+ Log.e(getLogTag(), "Bluetooth is not supported on this device");
+ return;
+ }
+ updateBluetooth();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (mLocalManager == null) {
+ Log.e(getLogTag(), "Bluetooth is not supported on this device");
+ return;
+ }
+ disableScanning();
+ }
+
+ @Override
+ public void onBluetoothStateChanged(int bluetoothState) {
+ super.onBluetoothStateChanged(bluetoothState);
+ updateContent(bluetoothState);
+ if (bluetoothState == BluetoothAdapter.STATE_ON) {
+ showBluetoothTurnedOnToast();
+ }
+ }
+
+ @Override
+ public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
+ if (bondState == BluetoothDevice.BOND_BONDED) {
+ // If one device is connected(bonded), then close this fragment.
+ finish();
+ return;
+ } else if (bondState == BluetoothDevice.BOND_BONDING) {
+ // Set the bond entry where binding process starts for logging hearing aid device info
+ final int pageId = FeatureFactory.getFactory(
+ getContext()).getMetricsFeatureProvider().getAttribution(getActivity());
+ final int bondEntry = AccessibilityStatsLogUtils.convertToHearingAidInfoBondEntry(
+ pageId);
+ HearingAidStatsLogUtils.setBondEntryForDevice(bondEntry, cachedDevice);
+ }
+ if (mSelectedDevice != null && cachedDevice != null) {
+ BluetoothDevice device = cachedDevice.getDevice();
+ if (device != null && mSelectedDevice.equals(device)
+ && bondState == BluetoothDevice.BOND_NONE) {
+ // If currently selected device failed to bond, restart scanning
+ enableScanning();
+ }
+ }
+ }
+
+ @Override
+ public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state,
+ int bluetoothProfile) {
+ // This callback is used to handle the case that bonded device is connected in pairing list.
+ // 1. If user selected multiple bonded devices in pairing list, after connected
+ // finish this page.
+ // 2. If the bonded devices auto connected in paring list, after connected it will be
+ // removed from paring list.
+ if (cachedDevice != null && cachedDevice.isConnected()) {
+ final BluetoothDevice device = cachedDevice.getDevice();
+ if (device != null && mSelectedList.contains(device)) {
+ finish();
+ } else if (mDevicePreferenceMap.containsKey(cachedDevice)) {
+ onDeviceDeleted(cachedDevice);
+ }
+ }
+ }
+
+ @Override
+ public void enableScanning() {
+ // Clear all device states before first scan
+ if (!mInitialScanStarted) {
+ if (mAvailableDevicesCategory != null) {
+ removeAllDevices();
+ }
+ mLocalManager.getCachedDeviceManager().clearNonBondedDevices();
+ mInitialScanStarted = true;
+ }
+ super.enableScanning();
+ }
+
+ @Override
+ public void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
+ disableScanning();
+ super.onDevicePreferenceClick(btPreference);
+ }
+
+ @VisibleForTesting
+ void updateBluetooth() {
+ if (mBluetoothAdapter.isEnabled()) {
+ updateContent(mBluetoothAdapter.getState());
+ } else {
+ // Turn on bluetooth if it is disabled
+ mBluetoothAdapter.enable();
+ }
+ }
+
+ /**
+ * Enables the scanning when {@code bluetoothState} is on, or finish the page when
+ * {@code bluetoothState} is off.
+ *
+ * @param bluetoothState the current Bluetooth state, the possible values that will handle here:
+ * {@link android.bluetooth.BluetoothAdapter#STATE_OFF},
+ * {@link android.bluetooth.BluetoothAdapter#STATE_ON},
+ */
+ @VisibleForTesting
+ public void updateContent(int bluetoothState) {
+ switch (bluetoothState) {
+ case BluetoothAdapter.STATE_ON:
+ mDevicePreferenceMap.clear();
+ clearPreferenceGroupCache();
+ mBluetoothAdapter.enable();
+ enableScanning();
+ break;
+
+ case BluetoothAdapter.STATE_OFF:
+ finish();
+ break;
+ }
+ }
+
+ /**
+ * Clears all cached preferences in {@code preferenceGroup}.
+ */
+ private void clearPreferenceGroupCache() {
+ cacheRemoveAllPrefs(mAvailableDevicesCategory);
+ removeCachedPrefs(mAvailableDevicesCategory);
+ }
+
+ @VisibleForTesting
+ void showBluetoothTurnedOnToast() {
+ Toast.makeText(getContext(), R.string.connected_device_bluetooth_turned_on_toast,
+ Toast.LENGTH_SHORT).show();
+ }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDetail.java b/src/com/android/settings/bluetooth/BluetoothPairingDetail.java
index 9a92783..a78bf27 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingDetail.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDetail.java
@@ -16,31 +16,25 @@
package com.android.settings.bluetooth;
-import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
-
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.os.Bundle;
-import android.util.Log;
-import android.widget.Toast;
+import android.view.View;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
-import com.android.settings.accessibility.AccessibilityStatsLogUtils;
-import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.HearingAidStatsLogUtils;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.widget.FooterPreference;
/**
* BluetoothPairingDetail is a page to scan bluetooth devices and pair them.
*/
-public class BluetoothPairingDetail extends DeviceListPreferenceFragment implements
+public class BluetoothPairingDetail extends BluetoothDevicePairingDetailBase implements
Indexable {
private static final String TAG = "BluetoothPairingDetail";
@@ -50,34 +44,12 @@
static final String KEY_FOOTER_PREF = "footer_preference";
@VisibleForTesting
- BluetoothProgressCategory mAvailableDevicesCategory;
- @VisibleForTesting
FooterPreference mFooterPreference;
@VisibleForTesting
AlwaysDiscoverable mAlwaysDiscoverable;
- private boolean mInitialScanStarted;
-
public BluetoothPairingDetail() {
- super(DISALLOW_CONFIG_BLUETOOTH);
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- mInitialScanStarted = false;
- mAlwaysDiscoverable = new AlwaysDiscoverable(getContext());
- }
-
- @Override
- public void onStart() {
- super.onStart();
- if (mLocalManager == null){
- Log.e(TAG, "Bluetooth is not supported on this device");
- return;
- }
- updateBluetooth();
- mAvailableDevicesCategory.setProgress(mBluetoothAdapter.isDiscovering());
+ super();
}
@Override
@@ -86,32 +58,29 @@
use(BluetoothDeviceRenamePreferenceController.class).setFragment(this);
}
- @VisibleForTesting
- void updateBluetooth() {
- if (mBluetoothAdapter.isEnabled()) {
- updateContent(mBluetoothAdapter.getState());
- } else {
- // Turn on bluetooth if it is disabled
- mBluetoothAdapter.enable();
- }
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ mAlwaysDiscoverable = new AlwaysDiscoverable(getContext());
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ mAvailableDevicesCategory.setProgress(mBluetoothAdapter.isDiscovering());
}
@Override
public void onStop() {
super.onStop();
- if (mLocalManager == null){
- Log.e(TAG, "Bluetooth is not supported on this device");
- return;
- }
// Make the device only visible to connected devices.
mAlwaysDiscoverable.stop();
- disableScanning();
}
@Override
- void initPreferencesFromPreferenceScreen() {
- mAvailableDevicesCategory = (BluetoothProgressCategory) findPreference(KEY_AVAIL_DEVICES);
- mFooterPreference = (FooterPreference) findPreference(KEY_FOOTER_PREF);
+ public void initPreferencesFromPreferenceScreen() {
+ super.initPreferencesFromPreferenceScreen();
+ mFooterPreference = findPreference(KEY_FOOTER_PREF);
mFooterPreference.setSelectable(false);
}
@@ -120,23 +89,25 @@
return SettingsEnums.BLUETOOTH_PAIRING;
}
+ /**
+ * {@inheritDoc}
+ *
+ * Will update footer and keep the device discoverable as long as the page is visible.
+ */
+ @VisibleForTesting
@Override
- void enableScanning() {
- // Clear all device states before first scan
- if (!mInitialScanStarted) {
- if (mAvailableDevicesCategory != null) {
- removeAllDevices();
+ public void updateContent(int bluetoothState) {
+ super.updateContent(bluetoothState);
+ if (bluetoothState == BluetoothAdapter.STATE_ON) {
+ if (mInitialScanStarted) {
+ // Don't show bonded devices when screen turned back on
+ setFilter(BluetoothDeviceFilter.UNBONDED_DEVICE_FILTER);
+ addCachedDevices();
}
- mLocalManager.getCachedDeviceManager().clearNonBondedDevices();
- mInitialScanStarted = true;
+ setFilter(BluetoothDeviceFilter.ALL_FILTER);
+ updateFooterPreference(mFooterPreference);
+ mAlwaysDiscoverable.start();
}
- super.enableScanning();
- }
-
- @Override
- void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
- disableScanning();
- super.onDevicePreferenceClick(btPreference);
}
@Override
@@ -146,78 +117,6 @@
mAvailableDevicesCategory.setProgress(started);
}
- @VisibleForTesting
- void updateContent(int bluetoothState) {
- switch (bluetoothState) {
- case BluetoothAdapter.STATE_ON:
- mDevicePreferenceMap.clear();
- mBluetoothAdapter.enable();
-
- addDeviceCategory(mAvailableDevicesCategory,
- R.string.bluetooth_preference_found_media_devices,
- BluetoothDeviceFilter.ALL_FILTER, mInitialScanStarted);
- updateFooterPreference(mFooterPreference);
- mAlwaysDiscoverable.start();
- enableScanning();
- break;
-
- case BluetoothAdapter.STATE_OFF:
- finish();
- break;
- }
- }
-
- @Override
- public void onBluetoothStateChanged(int bluetoothState) {
- super.onBluetoothStateChanged(bluetoothState);
- updateContent(bluetoothState);
- if (bluetoothState == BluetoothAdapter.STATE_ON) {
- showBluetoothTurnedOnToast();
- }
- }
-
- @Override
- public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
- if (bondState == BluetoothDevice.BOND_BONDED) {
- // If one device is connected(bonded), then close this fragment.
- finish();
- return;
- } else if (bondState == BluetoothDevice.BOND_BONDING) {
- // Set the bond entry where binding process starts for logging hearing aid device info
- final int pageId = FeatureFactory.getFactory(
- getContext()).getMetricsFeatureProvider().getAttribution(getActivity());
- final int bondEntry = AccessibilityStatsLogUtils.convertToHearingAidInfoBondEntry(
- pageId);
- HearingAidStatsLogUtils.setBondEntryForDevice(bondEntry, cachedDevice);
- }
- if (mSelectedDevice != null && cachedDevice != null) {
- BluetoothDevice device = cachedDevice.getDevice();
- if (device != null && mSelectedDevice.equals(device)
- && bondState == BluetoothDevice.BOND_NONE) {
- // If currently selected device failed to bond, restart scanning
- enableScanning();
- }
- }
- }
-
- @Override
- public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state,
- int bluetoothProfile) {
- // This callback is used to handle the case that bonded device is connected in pairing list.
- // 1. If user selected multiple bonded devices in pairing list, after connected
- // finish this page.
- // 2. If the bonded devices auto connected in paring list, after connected it will be
- // removed from paring list.
- if (cachedDevice != null && cachedDevice.isConnected()) {
- final BluetoothDevice device = cachedDevice.getDevice();
- if (device != null && mSelectedList.contains(device)) {
- finish();
- } else if (mDevicePreferenceMap.containsKey(cachedDevice)) {
- onDeviceDeleted(cachedDevice);
- }
- }
- }
-
@Override
public int getHelpResource() {
return R.string.help_url_bluetooth;
@@ -237,10 +136,4 @@
public String getDeviceListKey() {
return KEY_AVAIL_DEVICES;
}
-
- @VisibleForTesting
- void showBluetoothTurnedOnToast() {
- Toast.makeText(getContext(), R.string.connected_device_bluetooth_turned_on_toast,
- Toast.LENGTH_SHORT).show();
- }
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
new file mode 100644
index 0000000..184f521
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
@@ -0,0 +1,266 @@
+/*
+ * 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 com.android.settings.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.util.Pair;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
+
+/** Tests for {@link BluetoothDevicePairingDetailBase}. */
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
+public class BluetoothDevicePairingDetailBaseTest {
+
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ public static final String KEY_DEVICE_LIST_GROUP = "test_key";
+
+ private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
+ private static final String TEST_DEVICE_ADDRESS_B = "00:B1:B1:B1:B1:B1";
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+
+ @Mock
+ private Resources mResource;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private LocalBluetoothManager mLocalManager;
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+ @Mock
+ private Drawable mDrawable;
+ private BluetoothAdapter mBluetoothAdapter;
+ private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+ private BluetoothProgressCategory mAvailableDevicesCategory;
+ private BluetoothDevice mBluetoothDevice;
+ private TestBluetoothDevicePairingDetailBase mFragment;
+
+ @Before
+ public void setUp() {
+ mAvailableDevicesCategory = spy(new BluetoothProgressCategory(mContext));
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+ when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
+ final Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device");
+ when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pairs);
+ mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
+
+ mFragment = spy(new TestBluetoothDevicePairingDetailBase());
+ when(mFragment.findPreference(KEY_DEVICE_LIST_GROUP)).thenReturn(mAvailableDevicesCategory);
+ doReturn(mContext).when(mFragment).getContext();
+ doReturn(mResource).when(mFragment).getResources();
+ mFragment.mDeviceListGroup = mAvailableDevicesCategory;
+ mFragment.mLocalManager = mLocalManager;
+ mFragment.mBluetoothAdapter = mBluetoothAdapter;
+ mFragment.initPreferencesFromPreferenceScreen();
+
+ }
+
+ @Test
+ public void startScanning_startScanAndRemoveDevices() {
+ mFragment.enableScanning();
+
+ verify(mFragment).startScanning();
+ verify(mAvailableDevicesCategory).removeAll();
+ }
+
+ @Test
+ public void updateContent_stateOn() {
+ mFragment.updateContent(BluetoothAdapter.STATE_ON);
+
+ assertThat(mBluetoothAdapter.isEnabled()).isTrue();
+ verify(mFragment).enableScanning();
+ }
+
+ @Test
+ public void updateContent_stateOff_finish() {
+ mFragment.updateContent(BluetoothAdapter.STATE_OFF);
+
+ verify(mFragment).finish();
+ }
+
+ @Test
+ public void updateBluetooth_bluetoothOff_turnOnBluetooth() {
+ mShadowBluetoothAdapter.setEnabled(false);
+
+ mFragment.updateBluetooth();
+
+ assertThat(mBluetoothAdapter.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void updateBluetooth_bluetoothOn_updateState() {
+ mShadowBluetoothAdapter.setEnabled(true);
+ doNothing().when(mFragment).updateContent(anyInt());
+
+ mFragment.updateBluetooth();
+
+ verify(mFragment).updateContent(anyInt());
+ }
+
+ @Test
+ public void onBluetoothStateChanged_whenTurnedOnBTShowToast() {
+ doNothing().when(mFragment).updateContent(anyInt());
+
+ mFragment.onBluetoothStateChanged(BluetoothAdapter.STATE_ON);
+
+ verify(mFragment).showBluetoothTurnedOnToast();
+ }
+
+ @Test
+ public void onProfileConnectionStateChanged_deviceInSelectedListAndConnected_finish() {
+ final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
+ mFragment.mSelectedList.add(mBluetoothDevice);
+ mFragment.mSelectedList.add(device);
+
+ when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
+
+ mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+ BluetoothProfile.A2DP, BluetoothAdapter.STATE_CONNECTED);
+
+ verify(mFragment).finish();
+ }
+
+ @Test
+ public void onProfileConnectionStateChanged_deviceNotInSelectedList_doNothing() {
+ final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
+ mFragment.mSelectedList.add(device);
+
+ when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+
+ mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+ BluetoothProfile.A2DP, BluetoothAdapter.STATE_CONNECTED);
+
+ // not crash
+ }
+
+ @Test
+ public void onProfileConnectionStateChanged_deviceDisconnected_doNothing() {
+ final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
+ mFragment.mSelectedList.add(mBluetoothDevice);
+ mFragment.mSelectedList.add(device);
+
+ when(mCachedBluetoothDevice.isConnected()).thenReturn(false);
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
+
+ mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+ BluetoothProfile.A2DP, BluetoothAdapter.STATE_DISCONNECTED);
+
+ // not crash
+ }
+
+ @Test
+ public void onProfileConnectionStateChanged_deviceInPreferenceMapAndConnected_removed() {
+ final BluetoothDevicePreference preference =
+ new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
+ true, BluetoothDevicePreference.SortType.TYPE_FIFO);
+ final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
+ mFragment.mDevicePreferenceMap.put(mCachedBluetoothDevice, preference);
+
+ when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
+
+ mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+ BluetoothProfile.A2DP, BluetoothAdapter.STATE_CONNECTED);
+
+ assertThat(mFragment.mDevicePreferenceMap.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void onProfileConnectionStateChanged_deviceNotInPreferenceMap_doNothing() {
+ final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+ final BluetoothDevicePreference preference =
+ new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
+ true, BluetoothDevicePreference.SortType.TYPE_FIFO);
+ final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
+ final BluetoothDevice device2 = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
+ mFragment.mDevicePreferenceMap.put(mCachedBluetoothDevice, preference);
+
+ when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
+ when(cachedDevice.isConnected()).thenReturn(true);
+ when(cachedDevice.getDevice()).thenReturn(device2);
+ when(cachedDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS_B);
+ when(cachedDevice.getIdentityAddress()).thenReturn(TEST_DEVICE_ADDRESS_B);
+
+ mFragment.onProfileConnectionStateChanged(cachedDevice, BluetoothProfile.A2DP,
+ BluetoothAdapter.STATE_CONNECTED);
+
+ // not crash
+ }
+
+ private static class TestBluetoothDevicePairingDetailBase extends
+ BluetoothDevicePairingDetailBase {
+
+ TestBluetoothDevicePairingDetailBase() {
+ super();
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return 0;
+ }
+
+ @Override
+ public String getDeviceListKey() {
+ return KEY_DEVICE_LIST_GROUP;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return 0;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return "test_tag";
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDetailTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDetailTest.java
index bac868f..865ed81 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDetailTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDetailTest.java
@@ -18,102 +18,66 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.util.Pair;
+import android.os.Bundle;
-import androidx.preference.PreferenceGroup;
+import androidx.test.core.app.ApplicationProvider;
-import com.android.settings.R;
-import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
-import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.widget.FooterPreference;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadow.api.Shadow;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowBluetoothAdapter.class})
public class BluetoothPairingDetailTest {
- private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
- private static final String TEST_DEVICE_ADDRESS_B = "00:B1:B1:B1:B1:B1";
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
- @Mock
- private Resources mResource;
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private LocalBluetoothManager mLocalManager;
- @Mock
- private PreferenceGroup mPreferenceGroup;
- @Mock
- private CachedBluetoothDevice mCachedBluetoothDevice;
- @Mock
- private Drawable mDrawable;
-
private BluetoothPairingDetail mFragment;
- private Context mContext;
private BluetoothProgressCategory mAvailableDevicesCategory;
private FooterPreference mFooterPreference;
private BluetoothAdapter mBluetoothAdapter;
- private ShadowBluetoothAdapter mShadowBluetoothAdapter;
- private BluetoothDevice mBluetoothDevice;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device");
- mContext = RuntimeEnvironment.application;
mFragment = spy(new BluetoothPairingDetail());
doReturn(mContext).when(mFragment).getContext();
- doReturn(mResource).when(mFragment).getResources();
- when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
- when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pairs);
-
mAvailableDevicesCategory = spy(new BluetoothProgressCategory(mContext));
mFooterPreference = new FooterPreference(mContext);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
- mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
+
+ doReturn(mAvailableDevicesCategory).when(mFragment)
+ .findPreference(BluetoothPairingDetail.KEY_AVAIL_DEVICES);
+ doReturn(mFooterPreference).when(mFragment)
+ .findPreference(BluetoothPairingDetail.KEY_FOOTER_PREF);
mFragment.mBluetoothAdapter = mBluetoothAdapter;
mFragment.mLocalManager = mLocalManager;
- mFragment.mDeviceListGroup = mPreferenceGroup;
- mFragment.mAlwaysDiscoverable = new AlwaysDiscoverable(mContext);
+ mFragment.mDeviceListGroup = mAvailableDevicesCategory;
+ mFragment.onViewCreated(mFragment.getView(), Bundle.EMPTY);
}
-
+//
@Test
public void initPreferencesFromPreferenceScreen_findPreferences() {
- doReturn(mAvailableDevicesCategory).when(mFragment)
- .findPreference(BluetoothPairingDetail.KEY_AVAIL_DEVICES);
- doReturn(mFooterPreference).when(mFragment)
- .findPreference(BluetoothPairingDetail.KEY_FOOTER_PREF);
-
mFragment.initPreferencesFromPreferenceScreen();
assertThat(mFragment.mAvailableDevicesCategory).isEqualTo(mAvailableDevicesCategory);
@@ -121,63 +85,19 @@
}
@Test
- public void startScanning_startScanAndRemoveDevices() {
- mFragment.mAvailableDevicesCategory = mAvailableDevicesCategory;
- mFragment.mDeviceListGroup = mAvailableDevicesCategory;
-
- mFragment.enableScanning();
-
- verify(mFragment).startScanning();
- verify(mAvailableDevicesCategory).removeAll();
- }
-
- @Test
public void updateContent_stateOn_addDevices() {
- mFragment.mAvailableDevicesCategory = mAvailableDevicesCategory;
- mFragment.mFooterPreference = mFooterPreference;
- doNothing().when(mFragment).addDeviceCategory(any(), anyInt(), any(), anyBoolean());
+ mFragment.initPreferencesFromPreferenceScreen();
mFragment.updateContent(BluetoothAdapter.STATE_ON);
- verify(mFragment).addDeviceCategory(mAvailableDevicesCategory,
- R.string.bluetooth_preference_found_media_devices,
- BluetoothDeviceFilter.ALL_FILTER, false);
+ assertThat(mFragment.mAlwaysDiscoverable.mStarted).isEqualTo(true);
assertThat(mBluetoothAdapter.getScanMode())
.isEqualTo(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
}
@Test
- public void updateContent_stateOff_finish() {
- mFragment.updateContent(BluetoothAdapter.STATE_OFF);
-
- verify(mFragment).finish();
- }
-
- @Test
- public void updateBluetooth_bluetoothOff_turnOnBluetooth() {
- mShadowBluetoothAdapter.setEnabled(false);
-
- mFragment.updateBluetooth();
-
- assertThat(mBluetoothAdapter.isEnabled()).isTrue();
- }
-
- @Test
- public void updateBluetooth_bluetoothOn_updateState() {
- mShadowBluetoothAdapter.setEnabled(true);
- doNothing().when(mFragment).updateContent(anyInt());
-
- mFragment.updateBluetooth();
-
- verify(mFragment).updateContent(anyInt());
- }
-
- @Test
public void onScanningStateChanged_restartScanAfterInitialScanning() {
- mFragment.mAvailableDevicesCategory = mAvailableDevicesCategory;
- mFragment.mFooterPreference = mFooterPreference;
- mFragment.mDeviceListGroup = mAvailableDevicesCategory;
- doNothing().when(mFragment).addDeviceCategory(any(), anyInt(), any(), anyBoolean());
+ mFragment.initPreferencesFromPreferenceScreen();
// Initial Bluetooth ON will trigger scan enable, list clear and scan start
mFragment.updateContent(BluetoothAdapter.STATE_ON);
@@ -219,97 +139,4 @@
// Verify that clean up only happen once at initialization
verify(mAvailableDevicesCategory, times(1)).removeAll();
}
-
- @Test
- public void onBluetoothStateChanged_whenTurnedOnBTShowToast() {
- doNothing().when(mFragment).updateContent(anyInt());
-
- mFragment.onBluetoothStateChanged(BluetoothAdapter.STATE_ON);
-
- verify(mFragment).showBluetoothTurnedOnToast();
- }
-
- @Test
- public void onProfileConnectionStateChanged_deviceInSelectedListAndConnected_finish() {
- final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
- mFragment.mSelectedList.add(mBluetoothDevice);
- mFragment.mSelectedList.add(device);
-
- when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
- when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
-
- mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
- BluetoothProfile.A2DP, BluetoothAdapter.STATE_CONNECTED);
-
- verify(mFragment).finish();
- }
-
- @Test
- public void onProfileConnectionStateChanged_deviceNotInSelectedList_doNothing() {
- final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
- mFragment.mSelectedList.add(device);
-
- when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
- when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
-
- mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
- BluetoothProfile.A2DP, BluetoothAdapter.STATE_CONNECTED);
-
- // not crash
- }
-
- @Test
- public void onProfileConnectionStateChanged_deviceDisconnected_doNothing() {
- final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
- mFragment.mSelectedList.add(mBluetoothDevice);
- mFragment.mSelectedList.add(device);
-
- when(mCachedBluetoothDevice.isConnected()).thenReturn(false);
- when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
-
- mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
- BluetoothProfile.A2DP, BluetoothAdapter.STATE_DISCONNECTED);
-
- // not crash
- }
-
- @Test
- public void onProfileConnectionStateChanged_deviceInPreferenceMapAndConnected_removed() {
- final BluetoothDevicePreference preference =
- new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
- true, BluetoothDevicePreference.SortType.TYPE_FIFO);
- final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
- mFragment.mDevicePreferenceMap.put(mCachedBluetoothDevice, preference);
-
- when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
- when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
-
- mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
- BluetoothProfile.A2DP, BluetoothAdapter.STATE_CONNECTED);
-
- assertThat(mFragment.mDevicePreferenceMap.size()).isEqualTo(0);
- }
-
- @Test
- public void onProfileConnectionStateChanged_deviceNotInPreferenceMap_doNothing() {
- final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
- final BluetoothDevicePreference preference =
- new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
- true, BluetoothDevicePreference.SortType.TYPE_FIFO);
- final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
- final BluetoothDevice device2 = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
- mFragment.mDevicePreferenceMap.put(mCachedBluetoothDevice, preference);
-
- when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
- when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
- when(cachedDevice.isConnected()).thenReturn(true);
- when(cachedDevice.getDevice()).thenReturn(device2);
- when(cachedDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS_B);
- when(cachedDevice.getIdentityAddress()).thenReturn(TEST_DEVICE_ADDRESS_B);
-
- mFragment.onProfileConnectionStateChanged(cachedDevice, BluetoothProfile.A2DP,
- BluetoothAdapter.STATE_CONNECTED);
-
- // not crash
- }
}
\ No newline at end of file