Loading src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java +9 −9 Original line number Diff line number Diff line Loading @@ -89,7 +89,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll private LocalBluetoothManager mManager; private LocalBluetoothProfileManager mProfileManager; private CachedBluetoothDevice mCachedDevice; private List<CachedBluetoothDevice> mAllOfCachedDevices; private Set<CachedBluetoothDevice> mCachedDeviceGroup; private Map<String, List<CachedBluetoothDevice>> mProfileDeviceMap = new HashMap<String, List<CachedBluetoothDevice>>(); private boolean mIsLeContactSharingEnabled = false; Loading @@ -105,7 +105,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll mManager = manager; mProfileManager = mManager.getProfileManager(); mCachedDevice = device; mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice); } @Override Loading Loading @@ -310,10 +310,10 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll private List<LocalBluetoothProfile> getProfiles() { List<LocalBluetoothProfile> result = new ArrayList<>(); mProfileDeviceMap.clear(); if (mAllOfCachedDevices == null || mAllOfCachedDevices.isEmpty()) { if (mCachedDeviceGroup == null || mCachedDeviceGroup.isEmpty()) { return result; } for (CachedBluetoothDevice cachedItem : mAllOfCachedDevices) { for (CachedBluetoothDevice cachedItem : mCachedDeviceGroup) { List<LocalBluetoothProfile> tmpResult = cachedItem.getUiAccessibleProfiles(); for (LocalBluetoothProfile profile : tmpResult) { if (mProfileDeviceMap.containsKey(profile.toString())) { Loading Loading @@ -514,7 +514,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll @Override public void onPause() { for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.unregisterCallback(this); } mProfileManager.removeServiceListener(this); Loading @@ -523,7 +523,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll @Override public void onResume() { updateLeAudioConfig(); for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.registerCallback(this); } mProfileManager.addServiceListener(this); Loading @@ -545,11 +545,11 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll @Override public void onDeviceAttributesChanged() { for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.unregisterCallback(this); } mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); for (CachedBluetoothDevice item : mAllOfCachedDevices) { mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice); for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.registerCallback(this); } Loading src/com/android/settings/bluetooth/BluetoothDevicePreference.java +37 −13 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import com.android.settings.R; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.GearPreference; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.utils.ThreadUtils; Loading @@ -55,6 +56,7 @@ import java.util.HashSet; import java.util.Set; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; /** * BluetoothDevicePreference is the preference type used to display each remote Loading @@ -76,7 +78,10 @@ public final class BluetoothDevicePreference extends GearPreference { } private final CachedBluetoothDevice mCachedDevice; private Set<CachedBluetoothDevice> mCachedDeviceGroup; private final UserManager mUserManager; private final LocalBluetoothManager mLocalBtManager; private Set<BluetoothDevice> mBluetoothDevices; @VisibleForTesting Loading Loading @@ -113,6 +118,21 @@ public final class BluetoothDevicePreference extends GearPreference { @Override public void onDeviceAttributesChanged() { onPreferenceAttributesChanged(); Set<CachedBluetoothDevice> newCachedDeviceGroup = new HashSet<>( Utils.findAllCachedBluetoothDevicesByGroupId(mLocalBtManager, mCachedDevice)); if (!mCachedDeviceGroup.equals(newCachedDeviceGroup)) { for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { cachedBluetoothDevice.unregisterCallback(this); } unregisterMetadataChangedListener(); mCachedDeviceGroup = newCachedDeviceGroup; for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { cachedBluetoothDevice.registerCallback(getContext().getMainExecutor(), this); } registerMetadataChangedListener(); } } } Loading @@ -121,6 +141,7 @@ public final class BluetoothDevicePreference extends GearPreference { super(context, null); mResources = getContext().getResources(); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mLocalBtManager = Utils.getLocalBluetoothManager(context); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mShowDevicesWithoutNames = showDeviceWithoutNames; Loading @@ -131,6 +152,8 @@ public final class BluetoothDevicePreference extends GearPreference { } mCachedDevice = cachedDevice; mCachedDeviceGroup = new HashSet<>( Utils.findAllCachedBluetoothDevicesByGroupId(mLocalBtManager, mCachedDevice)); mCallback = new BluetoothDevicePreferenceCallback(); mId = sNextId.getAndIncrement(); mType = type; Loading Loading @@ -164,7 +187,9 @@ public final class BluetoothDevicePreference extends GearPreference { protected void onPrepareForRemoval() { super.onPrepareForRemoval(); if (!mIsCallbackRemoved) { mCachedDevice.unregisterCallback(mCallback); for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { cachedBluetoothDevice.unregisterCallback(mCallback); } unregisterMetadataChangedListener(); mIsCallbackRemoved = true; } Loading @@ -178,7 +203,9 @@ public final class BluetoothDevicePreference extends GearPreference { public void onAttached() { super.onAttached(); if (mIsCallbackRemoved) { mCachedDevice.registerCallback(mCallback); for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { cachedBluetoothDevice.registerCallback(getContext().getMainExecutor(), mCallback); } registerMetadataChangedListener(); mIsCallbackRemoved = false; } Loading @@ -189,7 +216,9 @@ public final class BluetoothDevicePreference extends GearPreference { public void onDetached() { super.onDetached(); if (!mIsCallbackRemoved) { mCachedDevice.unregisterCallback(mCallback); for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { cachedBluetoothDevice.unregisterCallback(mCallback); } unregisterMetadataChangedListener(); mIsCallbackRemoved = true; } Loading @@ -200,16 +229,11 @@ public final class BluetoothDevicePreference extends GearPreference { Log.d(TAG, "No mBluetoothAdapter"); return; } if (mBluetoothDevices == null) { mBluetoothDevices = new HashSet<>(); } mBluetoothDevices.clear(); if (mCachedDevice.getDevice() != null) { mBluetoothDevices.add(mCachedDevice.getDevice()); } for (CachedBluetoothDevice cbd : mCachedDevice.getMemberDevice()) { mBluetoothDevices.add(cbd.getDevice()); } mBluetoothDevices = mCachedDeviceGroup.stream() .map(CachedBluetoothDevice::getDevice) .collect(Collectors.toCollection(HashSet::new)); if (mBluetoothDevices.isEmpty()) { Log.d(TAG, "No BT device to register."); return; Loading src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java +11 −11 Original line number Diff line number Diff line Loading @@ -47,7 +47,7 @@ import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.widget.LayoutPreference; import java.util.List; import java.util.Set; /** * This class adds a header with device name and status (connected/disconnected, etc.). Loading Loading @@ -90,7 +90,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr LayoutPreference mLayoutPreference; LocalBluetoothManager mManager; private CachedBluetoothDevice mCachedDevice; private List<CachedBluetoothDevice> mAllOfCachedDevices; private Set<CachedBluetoothDevice> mCachedDeviceGroup; @VisibleForTesting Handler mHandler = new Handler(Looper.getMainLooper()); @VisibleForTesting Loading Loading @@ -128,7 +128,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr return; } mIsRegisterCallback = true; for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.registerCallback(this); } refresh(); Loading @@ -139,7 +139,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr if (!mIsRegisterCallback) { return; } for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.unregisterCallback(this); } Loading @@ -155,7 +155,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr mCachedDevice = cachedBluetoothDevice; mManager = bluetoothManager; mProfileManager = bluetoothManager.getProfileManager(); mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice); } @VisibleForTesting Loading Loading @@ -230,7 +230,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr // Init the battery layouts. hideAllOfBatteryLayouts(); LeAudioProfile leAudioProfile = mProfileManager.getLeAudioProfile(); if (mAllOfCachedDevices.isEmpty()) { if (mCachedDeviceGroup.isEmpty()) { Log.e(TAG, "There is no LeAudioProfile."); return; } Loading @@ -244,7 +244,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr return; } for (CachedBluetoothDevice cachedDevice : mAllOfCachedDevices) { for (CachedBluetoothDevice cachedDevice : mCachedDeviceGroup) { int deviceId = leAudioProfile.getAudioLocation(cachedDevice.getDevice()); Log.d(TAG, "LeAudioDevices:" + cachedDevice.getDevice().getAnonymizedAddress() + ", deviceId:" + deviceId); Loading Loading @@ -300,15 +300,15 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr @Override public void onDeviceAttributesChanged() { for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.unregisterCallback(this); } mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); for (CachedBluetoothDevice item : mAllOfCachedDevices) { mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice); for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.registerCallback(this); } if (!mAllOfCachedDevices.isEmpty()) { if (!mCachedDeviceGroup.isEmpty()) { refresh(); } } Loading src/com/android/settings/bluetooth/Utils.java +9 −10 Original line number Diff line number Diff line Loading @@ -48,8 +48,9 @@ import com.android.settingslib.utils.ThreadUtils; import com.google.common.base.Supplier; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; Loading Loading @@ -239,12 +240,12 @@ public final class Utils { * @param cachedBluetoothDevice The main cachedBluetoothDevice. * @return all cachedBluetoothDevices with the same groupId. */ public static List<CachedBluetoothDevice> getAllOfCachedBluetoothDevices( public static Set<CachedBluetoothDevice> findAllCachedBluetoothDevicesByGroupId( LocalBluetoothManager localBtMgr, CachedBluetoothDevice cachedBluetoothDevice) { List<CachedBluetoothDevice> cachedBluetoothDevices = new ArrayList<>(); Set<CachedBluetoothDevice> cachedBluetoothDevices = new HashSet<>(); if (cachedBluetoothDevice == null) { Log.e(TAG, "getAllOfCachedBluetoothDevices: no cachedBluetoothDevice"); Log.e(TAG, "findAllCachedBluetoothDevicesByGroupId: no cachedBluetoothDevice"); return cachedBluetoothDevices; } int deviceGroupId = cachedBluetoothDevice.getGroupId(); Loading @@ -254,7 +255,7 @@ public final class Utils { } if (localBtMgr == null) { Log.e(TAG, "getAllOfCachedBluetoothDevices: no LocalBluetoothManager"); Log.e(TAG, "findAllCachedBluetoothDevicesByGroupId: no LocalBluetoothManager"); return cachedBluetoothDevices; } CachedBluetoothDevice mainDevice = Loading @@ -262,16 +263,14 @@ public final class Utils { .filter(cachedDevice -> cachedDevice.getGroupId() == deviceGroupId) .findFirst().orElse(null); if (mainDevice == null) { Log.e(TAG, "getAllOfCachedBluetoothDevices: groupId = " + deviceGroupId Log.e(TAG, "findAllCachedBluetoothDevicesByGroupId: groupId = " + deviceGroupId + ", no main device."); return cachedBluetoothDevices; } cachedBluetoothDevice = mainDevice; cachedBluetoothDevices.add(cachedBluetoothDevice); for (CachedBluetoothDevice member : cachedBluetoothDevice.getMemberDevice()) { cachedBluetoothDevices.add(member); } Log.d(TAG, "getAllOfCachedBluetoothDevices: groupId = " + deviceGroupId cachedBluetoothDevices.addAll(cachedBluetoothDevice.getMemberDevice()); Log.d(TAG, "findAllCachedBluetoothDevicesByGroupId: groupId = " + deviceGroupId + " , cachedBluetoothDevice = " + cachedBluetoothDevice + " , deviceList = " + cachedBluetoothDevices); return cachedBluetoothDevices; Loading tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java +138 −31 Original line number Diff line number Diff line Loading @@ -18,10 +18,10 @@ package com.android.settings.bluetooth; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; 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; Loading @@ -32,22 +32,31 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.os.UserManager; import android.util.Pair; import android.view.ContextThemeWrapper; import androidx.test.core.app.ApplicationProvider; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; 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.util.ReflectionHelpers; Loading @@ -57,18 +66,21 @@ import java.util.Comparator; import java.util.List; @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowAlertDialogCompat.class}) @Config(shadows = {ShadowAlertDialogCompat.class, com.android.settings.testutils.shadow.ShadowBluetoothUtils.class}) public class BluetoothDevicePreferenceTest { private static final boolean SHOW_DEVICES_WITHOUT_NAMES = true; private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C"; private static final String MAC_ADDRESS_2 = "05:52:C7:0B:D8:3C"; private static final String MAC_ADDRESS_3 = "06:52:C7:0B:D8:3C"; private static final String MAC_ADDRESS_4 = "07:52:C7:0B:D8:3C"; private static final String TEST_MAC_ADDRESS = "04:52:C7:0B:D8:3C"; private static final String TEST_MAC_ADDRESS_1 = "05:52:C7:0B:D8:3C"; private static final String TEST_MAC_ADDRESS_2 = "06:52:C7:0B:D8:3C"; private static final String TEST_MAC_ADDRESS_3 = "07:52:C7:0B:D8:3C"; private static final Comparator<BluetoothDevicePreference> COMPARATOR = Comparator.naturalOrder(); private static final String FAKE_DESCRIPTION = "fake_description"; private static final int TEST_DEVICE_GROUP_ID = 1; private Context mContext; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); @Mock private CachedBluetoothDevice mCachedBluetoothDevice; @Mock Loading @@ -89,35 +101,37 @@ public class BluetoothDevicePreferenceTest { private Drawable mDrawable; @Mock private BluetoothAdapter mBluetoothAdapter; @Mock private LocalBluetoothManager mLocalBluetoothManager; @Mock private CachedBluetoothDeviceManager mDeviceManager; private Context mContext = ApplicationProvider.getApplicationContext(); private FakeFeatureFactory mFakeFeatureFactory; private MetricsFeatureProvider mMetricsFeatureProvider; private BluetoothDevicePreference mPreference; private List<BluetoothDevicePreference> mPreferenceList = new ArrayList<>(); @Before public void setUp() { MockitoAnnotations.initMocks(this); Context context = spy(RuntimeEnvironment.application.getApplicationContext()); mContext = new ContextThemeWrapper(context, R.style.Theme_Settings); mContext.setTheme(R.style.Theme_Settings); mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mMetricsFeatureProvider = mFakeFeatureFactory.getMetricsFeatureProvider(); when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS); when(mCachedBluetoothDevice.getDrawableWithDescription()) .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); when(mCachedDevice1.getAddress()).thenReturn(MAC_ADDRESS_2); when(mCachedDevice1.getDrawableWithDescription()) .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); when(mCachedDevice1.getDevice()).thenReturn(mBluetoothDevice1); when(mCachedDevice2.getAddress()).thenReturn(MAC_ADDRESS_3); when(mCachedDevice2.getDrawableWithDescription()) .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); when(mCachedDevice2.getDevice()).thenReturn(mBluetoothDevice2); when(mCachedDevice3.getAddress()).thenReturn(MAC_ADDRESS_4); when(mCachedDevice3.getDrawableWithDescription()) .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); when(mCachedDevice3.getDevice()).thenReturn(mBluetoothDevice3); ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; mLocalBluetoothManager = Utils.getLocalBtManager(mContext); when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager); prepareCachedBluetoothDevice(mCachedBluetoothDevice, TEST_MAC_ADDRESS, new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice); prepareCachedBluetoothDevice(mCachedDevice1, TEST_MAC_ADDRESS_1, new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice1); prepareCachedBluetoothDevice(mCachedDevice2, TEST_MAC_ADDRESS_2, new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice2); prepareCachedBluetoothDevice(mCachedDevice3, TEST_MAC_ADDRESS_3, new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice3); when(mDeviceManager.getCachedDevicesCopy()).thenReturn( ImmutableList.of(mCachedBluetoothDevice)); mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); mPreference.mBluetoothAdapter = mBluetoothAdapter; Loading Loading @@ -301,7 +315,8 @@ public class BluetoothDevicePreferenceTest { // callback is not removed. mPreference.onAttached(); verify(mCachedBluetoothDevice, times(1)).registerCallback(any()); verify(mCachedBluetoothDevice, times(1)).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mBluetoothAdapter, times(1)).addOnMetadataChangedListener(any(), any(), any()); } Loading @@ -313,7 +328,99 @@ public class BluetoothDevicePreferenceTest { mPreference.onAttached(); verify(mCachedBluetoothDevice, times(1)).unregisterCallback(any()); verify(mCachedBluetoothDevice, times(2)).registerCallback(any()); verify(mCachedBluetoothDevice, times(2)).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mBluetoothAdapter, times(2)).addOnMetadataChangedListener(any(), any(), any()); } @Test public void onDeviceAttributesChanged_updatePreference() { when(mCachedBluetoothDevice.getName()).thenReturn("Name"); mPreference.onAttached(); final String updatedName = "updatedName"; when(mCachedBluetoothDevice.getName()).thenReturn(updatedName); getCachedBluetoothDeviceCallback().onDeviceAttributesChanged(); assertThat(mPreference.getTitle().toString()).isEqualTo(updatedName); } @Test public void onAttached_memberDevicesAdded_registerAllCallback() { when(mCachedBluetoothDevice.getMemberDevice()).thenReturn( ImmutableSet.of(mCachedDevice1, mCachedDevice2, mCachedDevice3)); when(mDeviceManager.getCachedDevicesCopy()).thenReturn( ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2, mCachedDevice3)); mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); mPreference.onAttached(); verify(mCachedBluetoothDevice).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mCachedDevice1).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mCachedDevice2).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mCachedDevice3).registerCallback(eq(mContext.getMainExecutor()), any()); } @Test public void onDetached_memberDevicesAdded_unregisterAllCallback() { when(mCachedBluetoothDevice.getMemberDevice()).thenReturn( ImmutableSet.of(mCachedDevice1, mCachedDevice2, mCachedDevice3)); when(mDeviceManager.getCachedDevicesCopy()).thenReturn( ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2, mCachedDevice3)); mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); mPreference.onAttached(); mPreference.onDetached(); verify(mCachedBluetoothDevice).unregisterCallback(any()); verify(mCachedDevice1).unregisterCallback(any()); verify(mCachedDevice2).unregisterCallback(any()); verify(mCachedDevice3).unregisterCallback(any()); } @Test public void onDeviceAttributesChanged_memberDevicesChanged_registerOnlyExistDeviceCallback() { when(mCachedBluetoothDevice.getMemberDevice()).thenReturn( ImmutableSet.of(mCachedDevice1, mCachedDevice2, mCachedDevice3)); when(mDeviceManager.getCachedDevicesCopy()).thenReturn( ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2, mCachedDevice3)); mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); mPreference.onAttached(); when(mCachedBluetoothDevice.getMemberDevice()).thenReturn( ImmutableSet.of(mCachedDevice1, mCachedDevice2)); when(mDeviceManager.getCachedDevicesCopy()).thenReturn( ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2)); getCachedBluetoothDeviceCallback().onDeviceAttributesChanged(); verify(mCachedBluetoothDevice, times(2)).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mCachedDevice1, times(2)).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mCachedDevice2, times(2)).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mCachedDevice3, times(1)).registerCallback(eq(mContext.getMainExecutor()), any()); } private void prepareCachedBluetoothDevice(CachedBluetoothDevice cachedDevice, String address, Pair<Drawable, String> drawableWithDescription, int groupId, BluetoothDevice bluetoothDevice) { when(cachedDevice.getAddress()).thenReturn(address); when(cachedDevice.getDrawableWithDescription()).thenReturn(drawableWithDescription); when(cachedDevice.getGroupId()).thenReturn(groupId); when(cachedDevice.getDevice()).thenReturn(bluetoothDevice); } private CachedBluetoothDevice.Callback getCachedBluetoothDeviceCallback() { ArgumentCaptor<CachedBluetoothDevice.Callback> callbackCaptor = ArgumentCaptor.forClass( CachedBluetoothDevice.Callback.class); verify(mCachedBluetoothDevice).registerCallback(eq(mContext.getMainExecutor()), callbackCaptor.capture()); return callbackCaptor.getValue(); } } Loading
src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java +9 −9 Original line number Diff line number Diff line Loading @@ -89,7 +89,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll private LocalBluetoothManager mManager; private LocalBluetoothProfileManager mProfileManager; private CachedBluetoothDevice mCachedDevice; private List<CachedBluetoothDevice> mAllOfCachedDevices; private Set<CachedBluetoothDevice> mCachedDeviceGroup; private Map<String, List<CachedBluetoothDevice>> mProfileDeviceMap = new HashMap<String, List<CachedBluetoothDevice>>(); private boolean mIsLeContactSharingEnabled = false; Loading @@ -105,7 +105,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll mManager = manager; mProfileManager = mManager.getProfileManager(); mCachedDevice = device; mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice); } @Override Loading Loading @@ -310,10 +310,10 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll private List<LocalBluetoothProfile> getProfiles() { List<LocalBluetoothProfile> result = new ArrayList<>(); mProfileDeviceMap.clear(); if (mAllOfCachedDevices == null || mAllOfCachedDevices.isEmpty()) { if (mCachedDeviceGroup == null || mCachedDeviceGroup.isEmpty()) { return result; } for (CachedBluetoothDevice cachedItem : mAllOfCachedDevices) { for (CachedBluetoothDevice cachedItem : mCachedDeviceGroup) { List<LocalBluetoothProfile> tmpResult = cachedItem.getUiAccessibleProfiles(); for (LocalBluetoothProfile profile : tmpResult) { if (mProfileDeviceMap.containsKey(profile.toString())) { Loading Loading @@ -514,7 +514,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll @Override public void onPause() { for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.unregisterCallback(this); } mProfileManager.removeServiceListener(this); Loading @@ -523,7 +523,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll @Override public void onResume() { updateLeAudioConfig(); for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.registerCallback(this); } mProfileManager.addServiceListener(this); Loading @@ -545,11 +545,11 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll @Override public void onDeviceAttributesChanged() { for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.unregisterCallback(this); } mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); for (CachedBluetoothDevice item : mAllOfCachedDevices) { mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice); for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.registerCallback(this); } Loading
src/com/android/settings/bluetooth/BluetoothDevicePreference.java +37 −13 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import com.android.settings.R; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.GearPreference; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.utils.ThreadUtils; Loading @@ -55,6 +56,7 @@ import java.util.HashSet; import java.util.Set; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; /** * BluetoothDevicePreference is the preference type used to display each remote Loading @@ -76,7 +78,10 @@ public final class BluetoothDevicePreference extends GearPreference { } private final CachedBluetoothDevice mCachedDevice; private Set<CachedBluetoothDevice> mCachedDeviceGroup; private final UserManager mUserManager; private final LocalBluetoothManager mLocalBtManager; private Set<BluetoothDevice> mBluetoothDevices; @VisibleForTesting Loading Loading @@ -113,6 +118,21 @@ public final class BluetoothDevicePreference extends GearPreference { @Override public void onDeviceAttributesChanged() { onPreferenceAttributesChanged(); Set<CachedBluetoothDevice> newCachedDeviceGroup = new HashSet<>( Utils.findAllCachedBluetoothDevicesByGroupId(mLocalBtManager, mCachedDevice)); if (!mCachedDeviceGroup.equals(newCachedDeviceGroup)) { for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { cachedBluetoothDevice.unregisterCallback(this); } unregisterMetadataChangedListener(); mCachedDeviceGroup = newCachedDeviceGroup; for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { cachedBluetoothDevice.registerCallback(getContext().getMainExecutor(), this); } registerMetadataChangedListener(); } } } Loading @@ -121,6 +141,7 @@ public final class BluetoothDevicePreference extends GearPreference { super(context, null); mResources = getContext().getResources(); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mLocalBtManager = Utils.getLocalBluetoothManager(context); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mShowDevicesWithoutNames = showDeviceWithoutNames; Loading @@ -131,6 +152,8 @@ public final class BluetoothDevicePreference extends GearPreference { } mCachedDevice = cachedDevice; mCachedDeviceGroup = new HashSet<>( Utils.findAllCachedBluetoothDevicesByGroupId(mLocalBtManager, mCachedDevice)); mCallback = new BluetoothDevicePreferenceCallback(); mId = sNextId.getAndIncrement(); mType = type; Loading Loading @@ -164,7 +187,9 @@ public final class BluetoothDevicePreference extends GearPreference { protected void onPrepareForRemoval() { super.onPrepareForRemoval(); if (!mIsCallbackRemoved) { mCachedDevice.unregisterCallback(mCallback); for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { cachedBluetoothDevice.unregisterCallback(mCallback); } unregisterMetadataChangedListener(); mIsCallbackRemoved = true; } Loading @@ -178,7 +203,9 @@ public final class BluetoothDevicePreference extends GearPreference { public void onAttached() { super.onAttached(); if (mIsCallbackRemoved) { mCachedDevice.registerCallback(mCallback); for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { cachedBluetoothDevice.registerCallback(getContext().getMainExecutor(), mCallback); } registerMetadataChangedListener(); mIsCallbackRemoved = false; } Loading @@ -189,7 +216,9 @@ public final class BluetoothDevicePreference extends GearPreference { public void onDetached() { super.onDetached(); if (!mIsCallbackRemoved) { mCachedDevice.unregisterCallback(mCallback); for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { cachedBluetoothDevice.unregisterCallback(mCallback); } unregisterMetadataChangedListener(); mIsCallbackRemoved = true; } Loading @@ -200,16 +229,11 @@ public final class BluetoothDevicePreference extends GearPreference { Log.d(TAG, "No mBluetoothAdapter"); return; } if (mBluetoothDevices == null) { mBluetoothDevices = new HashSet<>(); } mBluetoothDevices.clear(); if (mCachedDevice.getDevice() != null) { mBluetoothDevices.add(mCachedDevice.getDevice()); } for (CachedBluetoothDevice cbd : mCachedDevice.getMemberDevice()) { mBluetoothDevices.add(cbd.getDevice()); } mBluetoothDevices = mCachedDeviceGroup.stream() .map(CachedBluetoothDevice::getDevice) .collect(Collectors.toCollection(HashSet::new)); if (mBluetoothDevices.isEmpty()) { Log.d(TAG, "No BT device to register."); return; Loading
src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java +11 −11 Original line number Diff line number Diff line Loading @@ -47,7 +47,7 @@ import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.widget.LayoutPreference; import java.util.List; import java.util.Set; /** * This class adds a header with device name and status (connected/disconnected, etc.). Loading Loading @@ -90,7 +90,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr LayoutPreference mLayoutPreference; LocalBluetoothManager mManager; private CachedBluetoothDevice mCachedDevice; private List<CachedBluetoothDevice> mAllOfCachedDevices; private Set<CachedBluetoothDevice> mCachedDeviceGroup; @VisibleForTesting Handler mHandler = new Handler(Looper.getMainLooper()); @VisibleForTesting Loading Loading @@ -128,7 +128,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr return; } mIsRegisterCallback = true; for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.registerCallback(this); } refresh(); Loading @@ -139,7 +139,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr if (!mIsRegisterCallback) { return; } for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.unregisterCallback(this); } Loading @@ -155,7 +155,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr mCachedDevice = cachedBluetoothDevice; mManager = bluetoothManager; mProfileManager = bluetoothManager.getProfileManager(); mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice); } @VisibleForTesting Loading Loading @@ -230,7 +230,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr // Init the battery layouts. hideAllOfBatteryLayouts(); LeAudioProfile leAudioProfile = mProfileManager.getLeAudioProfile(); if (mAllOfCachedDevices.isEmpty()) { if (mCachedDeviceGroup.isEmpty()) { Log.e(TAG, "There is no LeAudioProfile."); return; } Loading @@ -244,7 +244,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr return; } for (CachedBluetoothDevice cachedDevice : mAllOfCachedDevices) { for (CachedBluetoothDevice cachedDevice : mCachedDeviceGroup) { int deviceId = leAudioProfile.getAudioLocation(cachedDevice.getDevice()); Log.d(TAG, "LeAudioDevices:" + cachedDevice.getDevice().getAnonymizedAddress() + ", deviceId:" + deviceId); Loading Loading @@ -300,15 +300,15 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr @Override public void onDeviceAttributesChanged() { for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.unregisterCallback(this); } mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); for (CachedBluetoothDevice item : mAllOfCachedDevices) { mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice); for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.registerCallback(this); } if (!mAllOfCachedDevices.isEmpty()) { if (!mCachedDeviceGroup.isEmpty()) { refresh(); } } Loading
src/com/android/settings/bluetooth/Utils.java +9 −10 Original line number Diff line number Diff line Loading @@ -48,8 +48,9 @@ import com.android.settingslib.utils.ThreadUtils; import com.google.common.base.Supplier; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; Loading Loading @@ -239,12 +240,12 @@ public final class Utils { * @param cachedBluetoothDevice The main cachedBluetoothDevice. * @return all cachedBluetoothDevices with the same groupId. */ public static List<CachedBluetoothDevice> getAllOfCachedBluetoothDevices( public static Set<CachedBluetoothDevice> findAllCachedBluetoothDevicesByGroupId( LocalBluetoothManager localBtMgr, CachedBluetoothDevice cachedBluetoothDevice) { List<CachedBluetoothDevice> cachedBluetoothDevices = new ArrayList<>(); Set<CachedBluetoothDevice> cachedBluetoothDevices = new HashSet<>(); if (cachedBluetoothDevice == null) { Log.e(TAG, "getAllOfCachedBluetoothDevices: no cachedBluetoothDevice"); Log.e(TAG, "findAllCachedBluetoothDevicesByGroupId: no cachedBluetoothDevice"); return cachedBluetoothDevices; } int deviceGroupId = cachedBluetoothDevice.getGroupId(); Loading @@ -254,7 +255,7 @@ public final class Utils { } if (localBtMgr == null) { Log.e(TAG, "getAllOfCachedBluetoothDevices: no LocalBluetoothManager"); Log.e(TAG, "findAllCachedBluetoothDevicesByGroupId: no LocalBluetoothManager"); return cachedBluetoothDevices; } CachedBluetoothDevice mainDevice = Loading @@ -262,16 +263,14 @@ public final class Utils { .filter(cachedDevice -> cachedDevice.getGroupId() == deviceGroupId) .findFirst().orElse(null); if (mainDevice == null) { Log.e(TAG, "getAllOfCachedBluetoothDevices: groupId = " + deviceGroupId Log.e(TAG, "findAllCachedBluetoothDevicesByGroupId: groupId = " + deviceGroupId + ", no main device."); return cachedBluetoothDevices; } cachedBluetoothDevice = mainDevice; cachedBluetoothDevices.add(cachedBluetoothDevice); for (CachedBluetoothDevice member : cachedBluetoothDevice.getMemberDevice()) { cachedBluetoothDevices.add(member); } Log.d(TAG, "getAllOfCachedBluetoothDevices: groupId = " + deviceGroupId cachedBluetoothDevices.addAll(cachedBluetoothDevice.getMemberDevice()); Log.d(TAG, "findAllCachedBluetoothDevicesByGroupId: groupId = " + deviceGroupId + " , cachedBluetoothDevice = " + cachedBluetoothDevice + " , deviceList = " + cachedBluetoothDevices); return cachedBluetoothDevices; Loading
tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java +138 −31 Original line number Diff line number Diff line Loading @@ -18,10 +18,10 @@ package com.android.settings.bluetooth; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; 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; Loading @@ -32,22 +32,31 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.os.UserManager; import android.util.Pair; import android.view.ContextThemeWrapper; import androidx.test.core.app.ApplicationProvider; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; 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.util.ReflectionHelpers; Loading @@ -57,18 +66,21 @@ import java.util.Comparator; import java.util.List; @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowAlertDialogCompat.class}) @Config(shadows = {ShadowAlertDialogCompat.class, com.android.settings.testutils.shadow.ShadowBluetoothUtils.class}) public class BluetoothDevicePreferenceTest { private static final boolean SHOW_DEVICES_WITHOUT_NAMES = true; private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C"; private static final String MAC_ADDRESS_2 = "05:52:C7:0B:D8:3C"; private static final String MAC_ADDRESS_3 = "06:52:C7:0B:D8:3C"; private static final String MAC_ADDRESS_4 = "07:52:C7:0B:D8:3C"; private static final String TEST_MAC_ADDRESS = "04:52:C7:0B:D8:3C"; private static final String TEST_MAC_ADDRESS_1 = "05:52:C7:0B:D8:3C"; private static final String TEST_MAC_ADDRESS_2 = "06:52:C7:0B:D8:3C"; private static final String TEST_MAC_ADDRESS_3 = "07:52:C7:0B:D8:3C"; private static final Comparator<BluetoothDevicePreference> COMPARATOR = Comparator.naturalOrder(); private static final String FAKE_DESCRIPTION = "fake_description"; private static final int TEST_DEVICE_GROUP_ID = 1; private Context mContext; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); @Mock private CachedBluetoothDevice mCachedBluetoothDevice; @Mock Loading @@ -89,35 +101,37 @@ public class BluetoothDevicePreferenceTest { private Drawable mDrawable; @Mock private BluetoothAdapter mBluetoothAdapter; @Mock private LocalBluetoothManager mLocalBluetoothManager; @Mock private CachedBluetoothDeviceManager mDeviceManager; private Context mContext = ApplicationProvider.getApplicationContext(); private FakeFeatureFactory mFakeFeatureFactory; private MetricsFeatureProvider mMetricsFeatureProvider; private BluetoothDevicePreference mPreference; private List<BluetoothDevicePreference> mPreferenceList = new ArrayList<>(); @Before public void setUp() { MockitoAnnotations.initMocks(this); Context context = spy(RuntimeEnvironment.application.getApplicationContext()); mContext = new ContextThemeWrapper(context, R.style.Theme_Settings); mContext.setTheme(R.style.Theme_Settings); mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mMetricsFeatureProvider = mFakeFeatureFactory.getMetricsFeatureProvider(); when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS); when(mCachedBluetoothDevice.getDrawableWithDescription()) .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); when(mCachedDevice1.getAddress()).thenReturn(MAC_ADDRESS_2); when(mCachedDevice1.getDrawableWithDescription()) .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); when(mCachedDevice1.getDevice()).thenReturn(mBluetoothDevice1); when(mCachedDevice2.getAddress()).thenReturn(MAC_ADDRESS_3); when(mCachedDevice2.getDrawableWithDescription()) .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); when(mCachedDevice2.getDevice()).thenReturn(mBluetoothDevice2); when(mCachedDevice3.getAddress()).thenReturn(MAC_ADDRESS_4); when(mCachedDevice3.getDrawableWithDescription()) .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); when(mCachedDevice3.getDevice()).thenReturn(mBluetoothDevice3); ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; mLocalBluetoothManager = Utils.getLocalBtManager(mContext); when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager); prepareCachedBluetoothDevice(mCachedBluetoothDevice, TEST_MAC_ADDRESS, new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice); prepareCachedBluetoothDevice(mCachedDevice1, TEST_MAC_ADDRESS_1, new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice1); prepareCachedBluetoothDevice(mCachedDevice2, TEST_MAC_ADDRESS_2, new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice2); prepareCachedBluetoothDevice(mCachedDevice3, TEST_MAC_ADDRESS_3, new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice3); when(mDeviceManager.getCachedDevicesCopy()).thenReturn( ImmutableList.of(mCachedBluetoothDevice)); mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); mPreference.mBluetoothAdapter = mBluetoothAdapter; Loading Loading @@ -301,7 +315,8 @@ public class BluetoothDevicePreferenceTest { // callback is not removed. mPreference.onAttached(); verify(mCachedBluetoothDevice, times(1)).registerCallback(any()); verify(mCachedBluetoothDevice, times(1)).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mBluetoothAdapter, times(1)).addOnMetadataChangedListener(any(), any(), any()); } Loading @@ -313,7 +328,99 @@ public class BluetoothDevicePreferenceTest { mPreference.onAttached(); verify(mCachedBluetoothDevice, times(1)).unregisterCallback(any()); verify(mCachedBluetoothDevice, times(2)).registerCallback(any()); verify(mCachedBluetoothDevice, times(2)).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mBluetoothAdapter, times(2)).addOnMetadataChangedListener(any(), any(), any()); } @Test public void onDeviceAttributesChanged_updatePreference() { when(mCachedBluetoothDevice.getName()).thenReturn("Name"); mPreference.onAttached(); final String updatedName = "updatedName"; when(mCachedBluetoothDevice.getName()).thenReturn(updatedName); getCachedBluetoothDeviceCallback().onDeviceAttributesChanged(); assertThat(mPreference.getTitle().toString()).isEqualTo(updatedName); } @Test public void onAttached_memberDevicesAdded_registerAllCallback() { when(mCachedBluetoothDevice.getMemberDevice()).thenReturn( ImmutableSet.of(mCachedDevice1, mCachedDevice2, mCachedDevice3)); when(mDeviceManager.getCachedDevicesCopy()).thenReturn( ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2, mCachedDevice3)); mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); mPreference.onAttached(); verify(mCachedBluetoothDevice).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mCachedDevice1).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mCachedDevice2).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mCachedDevice3).registerCallback(eq(mContext.getMainExecutor()), any()); } @Test public void onDetached_memberDevicesAdded_unregisterAllCallback() { when(mCachedBluetoothDevice.getMemberDevice()).thenReturn( ImmutableSet.of(mCachedDevice1, mCachedDevice2, mCachedDevice3)); when(mDeviceManager.getCachedDevicesCopy()).thenReturn( ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2, mCachedDevice3)); mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); mPreference.onAttached(); mPreference.onDetached(); verify(mCachedBluetoothDevice).unregisterCallback(any()); verify(mCachedDevice1).unregisterCallback(any()); verify(mCachedDevice2).unregisterCallback(any()); verify(mCachedDevice3).unregisterCallback(any()); } @Test public void onDeviceAttributesChanged_memberDevicesChanged_registerOnlyExistDeviceCallback() { when(mCachedBluetoothDevice.getMemberDevice()).thenReturn( ImmutableSet.of(mCachedDevice1, mCachedDevice2, mCachedDevice3)); when(mDeviceManager.getCachedDevicesCopy()).thenReturn( ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2, mCachedDevice3)); mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); mPreference.onAttached(); when(mCachedBluetoothDevice.getMemberDevice()).thenReturn( ImmutableSet.of(mCachedDevice1, mCachedDevice2)); when(mDeviceManager.getCachedDevicesCopy()).thenReturn( ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2)); getCachedBluetoothDeviceCallback().onDeviceAttributesChanged(); verify(mCachedBluetoothDevice, times(2)).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mCachedDevice1, times(2)).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mCachedDevice2, times(2)).registerCallback(eq(mContext.getMainExecutor()), any()); verify(mCachedDevice3, times(1)).registerCallback(eq(mContext.getMainExecutor()), any()); } private void prepareCachedBluetoothDevice(CachedBluetoothDevice cachedDevice, String address, Pair<Drawable, String> drawableWithDescription, int groupId, BluetoothDevice bluetoothDevice) { when(cachedDevice.getAddress()).thenReturn(address); when(cachedDevice.getDrawableWithDescription()).thenReturn(drawableWithDescription); when(cachedDevice.getGroupId()).thenReturn(groupId); when(cachedDevice.getDevice()).thenReturn(bluetoothDevice); } private CachedBluetoothDevice.Callback getCachedBluetoothDeviceCallback() { ArgumentCaptor<CachedBluetoothDevice.Callback> callbackCaptor = ArgumentCaptor.forClass( CachedBluetoothDevice.Callback.class); verify(mCachedBluetoothDevice).registerCallback(eq(mContext.getMainExecutor()), callbackCaptor.capture()); return callbackCaptor.getValue(); } }