1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 package com.android.settings.bluetooth; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.Mockito.doReturn; 22 import static org.mockito.Mockito.never; 23 import static org.mockito.Mockito.verify; 24 import static org.mockito.Mockito.when; 25 26 import android.bluetooth.BluetoothAdapter; 27 import android.bluetooth.BluetoothDevice; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.graphics.drawable.Drawable; 31 import android.util.Pair; 32 33 import androidx.preference.Preference; 34 35 import com.android.settings.SettingsActivity; 36 import com.android.settings.connecteddevice.DevicePreferenceCallback; 37 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; 38 import com.android.settingslib.bluetooth.CachedBluetoothDevice; 39 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; 40 import com.android.settingslib.bluetooth.LocalBluetoothManager; 41 42 import com.google.common.collect.ImmutableList; 43 44 import org.junit.Before; 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 import org.mockito.ArgumentCaptor; 48 import org.mockito.Mock; 49 import org.mockito.MockitoAnnotations; 50 import org.robolectric.RobolectricTestRunner; 51 import org.robolectric.RuntimeEnvironment; 52 import org.robolectric.annotation.Config; 53 import org.robolectric.shadow.api.Shadow; 54 55 import java.util.ArrayList; 56 import java.util.List; 57 58 @RunWith(RobolectricTestRunner.class) 59 @Config(shadows = {ShadowBluetoothAdapter.class}) 60 public class BluetoothDeviceUpdaterTest { 61 62 private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C"; 63 private static final String SUB_MAC_ADDRESS = "05:52:C7:0B:D8:3C"; 64 private static final String TEST_NAME = "test_name"; 65 66 @Mock 67 private DevicePreferenceCallback mDevicePreferenceCallback; 68 @Mock 69 private CachedBluetoothDevice mCachedBluetoothDevice; 70 @Mock 71 private CachedBluetoothDevice mSubCachedBluetoothDevice; 72 @Mock 73 private BluetoothDevice mBluetoothDevice; 74 @Mock 75 private BluetoothDevice mSubBluetoothDevice; 76 @Mock 77 private SettingsActivity mSettingsActivity; 78 @Mock 79 private LocalBluetoothManager mLocalManager; 80 @Mock 81 private CachedBluetoothDeviceManager mCachedDeviceManager; 82 @Mock 83 private Drawable mDrawable; 84 85 private Context mContext; 86 private TestBluetoothDeviceUpdater mBluetoothDeviceUpdater; 87 private BluetoothDevicePreference mPreference; 88 private ShadowBluetoothAdapter mShadowBluetoothAdapter; 89 private List<CachedBluetoothDevice> mCachedDevices = new ArrayList<>(); 90 91 @Before setUp()92 public void setUp() { 93 MockitoAnnotations.initMocks(this); 94 95 Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device"); 96 mContext = RuntimeEnvironment.application; 97 mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); 98 mCachedDevices.add(mCachedBluetoothDevice); 99 when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); 100 when(mSubCachedBluetoothDevice.getDevice()).thenReturn(mSubBluetoothDevice); 101 when(mLocalManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); 102 when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices); 103 when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS); 104 when(mBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS); 105 when(mSubBluetoothDevice.getAddress()).thenReturn(SUB_MAC_ADDRESS); 106 when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pairs); 107 108 mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, 109 /* showDeviceWithoutNames= */ false, 110 BluetoothDevicePreference.SortType.TYPE_DEFAULT); 111 mBluetoothDeviceUpdater = new TestBluetoothDeviceUpdater(mContext, 112 mDevicePreferenceCallback, mLocalManager, /* metricsCategory= */ 0); 113 mBluetoothDeviceUpdater.setPrefContext(mContext); 114 } 115 116 @Test testAddPreference_deviceExist_doNothing()117 public void testAddPreference_deviceExist_doNothing() { 118 mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference); 119 120 mBluetoothDeviceUpdater.addPreference(mCachedBluetoothDevice); 121 122 verify(mDevicePreferenceCallback, never()).onDeviceAdded(any(Preference.class)); 123 } 124 125 @Test testAddPreference_deviceNotExist_addPreference()126 public void testAddPreference_deviceNotExist_addPreference() { 127 mBluetoothDeviceUpdater.addPreference(mCachedBluetoothDevice); 128 129 final Preference preference = mBluetoothDeviceUpdater.mPreferenceMap.get(mBluetoothDevice); 130 assertThat(preference).isNotNull(); 131 verify(mDevicePreferenceCallback).onDeviceAdded(preference); 132 } 133 134 @Test testRemovePreference_deviceExist_removePreference()135 public void testRemovePreference_deviceExist_removePreference() { 136 mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference); 137 138 mBluetoothDeviceUpdater.removePreference(mCachedBluetoothDevice); 139 140 verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference); 141 assertThat(mBluetoothDeviceUpdater.mPreferenceMap.containsKey(mBluetoothDevice)).isFalse(); 142 } 143 144 @Test testOnDeviceDeleted_deviceExists_removePreference()145 public void testOnDeviceDeleted_deviceExists_removePreference() { 146 mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference); 147 148 mBluetoothDeviceUpdater.onDeviceDeleted(mCachedBluetoothDevice); 149 150 verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference); 151 assertThat(mBluetoothDeviceUpdater.mPreferenceMap.containsKey(mBluetoothDevice)).isFalse(); 152 } 153 154 @Test testRemovePreference_deviceNotExist_doNothing()155 public void testRemovePreference_deviceNotExist_doNothing() { 156 mBluetoothDeviceUpdater.removePreference(mCachedBluetoothDevice); 157 158 verify(mDevicePreferenceCallback, never()).onDeviceRemoved(any(Preference.class)); 159 } 160 161 @Test testRemovePreference_subDeviceExist_removePreference()162 public void testRemovePreference_subDeviceExist_removePreference() { 163 when(mCachedBluetoothDevice.getSubDevice()).thenReturn(mSubCachedBluetoothDevice); 164 mBluetoothDeviceUpdater.mPreferenceMap.put(mSubBluetoothDevice, mPreference); 165 166 assertThat(mBluetoothDeviceUpdater.mPreferenceMap. 167 containsKey(mSubBluetoothDevice)).isTrue(); 168 mBluetoothDeviceUpdater.removePreference(mCachedBluetoothDevice); 169 170 verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference); 171 assertThat(mBluetoothDeviceUpdater.mPreferenceMap. 172 containsKey(mSubBluetoothDevice)).isFalse(); 173 } 174 175 @Test testDeviceProfilesListener_click_startBluetoothDeviceDetailPage()176 public void testDeviceProfilesListener_click_startBluetoothDeviceDetailPage() { 177 mBluetoothDeviceUpdater = new TestBluetoothDeviceUpdater(mSettingsActivity, 178 mDevicePreferenceCallback, mLocalManager, /* metricsCategory= */ 0); 179 180 final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 181 mBluetoothDeviceUpdater.mDeviceProfilesListener.onGearClick(mPreference); 182 183 verify(mSettingsActivity).startActivity(intentCaptor.capture()); 184 assertThat(intentCaptor.getValue().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)) 185 .isEqualTo(BluetoothDeviceDetailsFragment.class.getName()); 186 } 187 188 @Test isDeviceConnected_deviceConnected()189 public void isDeviceConnected_deviceConnected() { 190 doReturn(BluetoothDevice.BOND_BONDED).when(mBluetoothDevice).getBondState(); 191 doReturn(true).when(mBluetoothDevice).isConnected(); 192 193 assertThat(mBluetoothDeviceUpdater.isDeviceConnected(mCachedBluetoothDevice)).isTrue(); 194 } 195 196 @Test isDeviceConnected_deviceNotConnected()197 public void isDeviceConnected_deviceNotConnected() { 198 doReturn(BluetoothDevice.BOND_BONDED).when(mBluetoothDevice).getBondState(); 199 doReturn(false).when(mBluetoothDevice).isConnected(); 200 201 assertThat(mBluetoothDeviceUpdater.isDeviceConnected(mCachedBluetoothDevice)).isFalse(); 202 } 203 204 @Test registerCallback_localBluetoothManagerNull_shouldNotCrash()205 public void registerCallback_localBluetoothManagerNull_shouldNotCrash() { 206 mBluetoothDeviceUpdater.mLocalManager = null; 207 208 // Shouldn't crash 209 mBluetoothDeviceUpdater.registerCallback(); 210 } 211 212 @Test unregisterCallback_localBluetoothManagerNull_shouldNotCrash()213 public void unregisterCallback_localBluetoothManagerNull_shouldNotCrash() { 214 mBluetoothDeviceUpdater.mLocalManager = null; 215 216 // Shouldn't crash 217 mBluetoothDeviceUpdater.unregisterCallback(); 218 } 219 220 @Test forceUpdate_bluetoothDisabled_removeAllDevicesFromPreference()221 public void forceUpdate_bluetoothDisabled_removeAllDevicesFromPreference() { 222 mShadowBluetoothAdapter.setEnabled(false); 223 mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference); 224 225 mBluetoothDeviceUpdater.forceUpdate(); 226 227 verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference); 228 assertThat(mBluetoothDeviceUpdater.mPreferenceMap).isEmpty(); 229 } 230 231 @Test forceUpdate_bluetoothEnabled_addPreference()232 public void forceUpdate_bluetoothEnabled_addPreference() { 233 mShadowBluetoothAdapter.setEnabled(true); 234 mBluetoothDeviceUpdater.forceUpdate(); 235 236 verify(mDevicePreferenceCallback).onDeviceAdded(any(Preference.class)); 237 } 238 239 @Test onBluetoothStateChanged_bluetoothStateIsOn_forceUpdate()240 public void onBluetoothStateChanged_bluetoothStateIsOn_forceUpdate() { 241 mShadowBluetoothAdapter.setEnabled(true); 242 mBluetoothDeviceUpdater.onBluetoothStateChanged(BluetoothAdapter.STATE_ON); 243 244 verify(mDevicePreferenceCallback).onDeviceAdded(any(Preference.class)); 245 } 246 247 @Test onBluetoothStateChanged_bluetoothStateIsOff_removeAllDevicesFromPreference()248 public void onBluetoothStateChanged_bluetoothStateIsOff_removeAllDevicesFromPreference() { 249 mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference); 250 251 mBluetoothDeviceUpdater.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF); 252 253 verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference); 254 assertThat(mBluetoothDeviceUpdater.mPreferenceMap.containsKey(mBluetoothDevice)).isFalse(); 255 } 256 257 @Test refreshPreference_havePreference_refresh()258 public void refreshPreference_havePreference_refresh() { 259 mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference); 260 mPreference.setTitle("fake_name"); 261 262 when(mCachedBluetoothDevice.getName()).thenReturn(TEST_NAME); 263 mBluetoothDeviceUpdater.refreshPreference(); 264 265 assertThat(mPreference.getTitle()).isEqualTo(TEST_NAME); 266 } 267 268 @Test refreshPreference_staledPreference_remove()269 public void refreshPreference_staledPreference_remove() { 270 mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference); 271 mPreference.setTitle("fake_name"); 272 273 when(mCachedBluetoothDevice.getName()).thenReturn(TEST_NAME); 274 when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(ImmutableList.of()); 275 mBluetoothDeviceUpdater.refreshPreference(); 276 277 verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference); 278 assertThat(mBluetoothDeviceUpdater.mPreferenceMap.containsKey(mBluetoothDevice)).isFalse(); 279 } 280 281 @Test refreshPreference_inconsistentPreference_doNothing()282 public void refreshPreference_inconsistentPreference_doNothing() { 283 when(mCachedBluetoothDevice.getDevice()).thenReturn(mSubBluetoothDevice); 284 mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference); 285 mBluetoothDeviceUpdater.mPreferenceMap.put(mSubBluetoothDevice, mPreference); 286 287 when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn( 288 ImmutableList.of(mSubCachedBluetoothDevice)); 289 mBluetoothDeviceUpdater.refreshPreference(); 290 291 verify(mDevicePreferenceCallback, never()).onDeviceRemoved(mPreference); 292 assertThat(mBluetoothDeviceUpdater.mPreferenceMap.containsKey(mBluetoothDevice)).isFalse(); 293 } 294 295 @Test refreshPreference_staledInconsistentPreference_remove()296 public void refreshPreference_staledInconsistentPreference_remove() { 297 when(mCachedBluetoothDevice.getDevice()).thenReturn(mSubBluetoothDevice); 298 mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference); 299 300 when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(ImmutableList.of()); 301 mBluetoothDeviceUpdater.refreshPreference(); 302 303 verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference); 304 assertThat(mBluetoothDeviceUpdater.mPreferenceMap.containsKey(mBluetoothDevice)).isFalse(); 305 } 306 307 public static class TestBluetoothDeviceUpdater extends BluetoothDeviceUpdater { TestBluetoothDeviceUpdater(Context context, DevicePreferenceCallback devicePreferenceCallback, LocalBluetoothManager localManager, int metricsCategory)308 public TestBluetoothDeviceUpdater(Context context, 309 DevicePreferenceCallback devicePreferenceCallback, 310 LocalBluetoothManager localManager, int metricsCategory) { 311 super(context, devicePreferenceCallback, localManager, metricsCategory); 312 } 313 314 @Override isFilterMatched(CachedBluetoothDevice cachedBluetoothDevice)315 public boolean isFilterMatched(CachedBluetoothDevice cachedBluetoothDevice) { 316 return true; 317 } 318 319 @Override getPreferenceKeyPrefix()320 protected String getPreferenceKeyPrefix() { 321 return "test_bt"; 322 } 323 } 324 } 325