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.doNothing; 22 import static org.mockito.Mockito.doReturn; 23 import static org.mockito.Mockito.doThrow; 24 import static org.mockito.Mockito.never; 25 import static org.mockito.Mockito.spy; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.when; 28 29 import android.bluetooth.BluetoothAdapter; 30 import android.bluetooth.BluetoothDevice; 31 import android.bluetooth.BluetoothProfile; 32 import android.content.Context; 33 import android.content.pm.ApplicationInfo; 34 import android.content.pm.PackageManager; 35 import android.graphics.drawable.Drawable; 36 import android.media.AudioManager; 37 import android.platform.test.annotations.RequiresFlagsEnabled; 38 import android.platform.test.flag.junit.CheckFlagsRule; 39 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 40 import android.util.Pair; 41 42 import com.android.settings.connecteddevice.DevicePreferenceCallback; 43 import com.android.settings.dashboard.DashboardFragment; 44 import com.android.settings.testutils.shadow.ShadowAudioManager; 45 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; 46 import com.android.settings.testutils.shadow.ShadowCachedBluetoothDeviceManager; 47 import com.android.settingslib.bluetooth.CachedBluetoothDevice; 48 import com.android.settingslib.flags.Flags; 49 50 import org.junit.Before; 51 import org.junit.Rule; 52 import org.junit.Test; 53 import org.junit.runner.RunWith; 54 import org.mockito.Mock; 55 import org.mockito.MockitoAnnotations; 56 import org.robolectric.RobolectricTestRunner; 57 import org.robolectric.RuntimeEnvironment; 58 import org.robolectric.annotation.Config; 59 import org.robolectric.shadow.api.Shadow; 60 61 import java.util.ArrayList; 62 import java.util.Collection; 63 64 @RunWith(RobolectricTestRunner.class) 65 @Config(shadows = {ShadowAudioManager.class, ShadowBluetoothAdapter.class, 66 ShadowCachedBluetoothDeviceManager.class}) 67 public class ConnectedBluetoothDeviceUpdaterTest { 68 69 private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C"; 70 private static final String TEST_EXCLUSIVE_MANAGER = "com.test.manager"; 71 72 @Rule 73 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 74 75 @Mock 76 private DashboardFragment mDashboardFragment; 77 @Mock 78 private DevicePreferenceCallback mDevicePreferenceCallback; 79 @Mock 80 private CachedBluetoothDevice mCachedBluetoothDevice; 81 @Mock 82 private BluetoothDevice mBluetoothDevice; 83 @Mock 84 private Drawable mDrawable; 85 @Mock 86 private PackageManager mPackageManager; 87 88 private Context mContext; 89 private ConnectedBluetoothDeviceUpdater mBluetoothDeviceUpdater; 90 private Collection<CachedBluetoothDevice> mCachedDevices; 91 private AudioManager mAudioManager; 92 private ShadowBluetoothAdapter mShadowBluetoothAdapter; 93 private ShadowCachedBluetoothDeviceManager mShadowCachedBluetoothDeviceManager; 94 95 @Before setUp()96 public void setUp() { 97 MockitoAnnotations.initMocks(this); 98 99 Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device"); 100 mContext = spy(RuntimeEnvironment.application); 101 mAudioManager = mContext.getSystemService(AudioManager.class); 102 mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); 103 mShadowBluetoothAdapter.setEnabled(true); 104 mShadowCachedBluetoothDeviceManager = Shadow.extract( 105 Utils.getLocalBtManager(mContext).getCachedDeviceManager()); 106 doReturn(mContext).when(mDashboardFragment).getContext(); 107 mCachedDevices = new ArrayList<>(); 108 mCachedDevices.add(mCachedBluetoothDevice); 109 110 when(mContext.getPackageManager()).thenReturn(mPackageManager); 111 when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); 112 when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS); 113 when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pairs); 114 mShadowCachedBluetoothDeviceManager.setCachedDevicesCopy(mCachedDevices); 115 mBluetoothDeviceUpdater = spy(new ConnectedBluetoothDeviceUpdater(mContext, 116 mDevicePreferenceCallback, /* metricsCategory= */ 0)); 117 mBluetoothDeviceUpdater.setPrefContext(mContext); 118 doNothing().when(mBluetoothDeviceUpdater).addPreference(any()); 119 doNothing().when(mBluetoothDeviceUpdater).removePreference(any()); 120 } 121 122 @Test onAudioModeChanged_hfpDeviceConnected_notInCall_addPreference()123 public void onAudioModeChanged_hfpDeviceConnected_notInCall_addPreference() { 124 mAudioManager.setMode(AudioManager.MODE_NORMAL); 125 when(mBluetoothDeviceUpdater. 126 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 127 when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true); 128 129 mBluetoothDeviceUpdater.onAudioModeChanged(); 130 131 verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); 132 } 133 134 @Test onAudioModeChanged_hfpDeviceConnected_inCall_removePreference()135 public void onAudioModeChanged_hfpDeviceConnected_inCall_removePreference() { 136 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 137 when(mBluetoothDeviceUpdater. 138 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 139 when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true); 140 141 mBluetoothDeviceUpdater.onAudioModeChanged(); 142 143 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 144 } 145 146 @Test onAudioModeChanged_a2dpDeviceConnected_notInCall_removePreference()147 public void onAudioModeChanged_a2dpDeviceConnected_notInCall_removePreference() { 148 mAudioManager.setMode(AudioManager.MODE_NORMAL); 149 when(mBluetoothDeviceUpdater. 150 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 151 when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true); 152 153 mBluetoothDeviceUpdater.onAudioModeChanged(); 154 155 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 156 } 157 158 @Test onAudioModeChanged_a2dpDeviceConnected_inCall_addPreference()159 public void onAudioModeChanged_a2dpDeviceConnected_inCall_addPreference() { 160 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 161 when(mBluetoothDeviceUpdater. 162 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 163 when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true); 164 165 mBluetoothDeviceUpdater.onAudioModeChanged(); 166 167 verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); 168 } 169 170 @Test onProfileConnectionStateChanged_a2dpDeviceConnected_inCall_addPreference()171 public void onProfileConnectionStateChanged_a2dpDeviceConnected_inCall_addPreference() { 172 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 173 when(mBluetoothDeviceUpdater. 174 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 175 when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true); 176 177 mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, 178 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); 179 180 verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); 181 } 182 183 @Test onProfileConnectionStateChanged_deviceIsNotInList_inCall_invokesRemovePreference()184 public void onProfileConnectionStateChanged_deviceIsNotInList_inCall_invokesRemovePreference() { 185 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 186 when(mBluetoothDeviceUpdater. 187 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 188 when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true); 189 mCachedDevices.clear(); 190 191 mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, 192 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); 193 194 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 195 } 196 197 @Test onProfileConnectionStateChanged_a2dpDeviceConnected_notInCall_removePreference()198 public void onProfileConnectionStateChanged_a2dpDeviceConnected_notInCall_removePreference() { 199 mAudioManager.setMode(AudioManager.MODE_NORMAL); 200 when(mBluetoothDeviceUpdater. 201 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 202 when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true); 203 204 mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, 205 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); 206 207 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 208 } 209 210 @Test onProfileConnectionStateChanged_hfpDeviceConnected_inCall_removePreference()211 public void onProfileConnectionStateChanged_hfpDeviceConnected_inCall_removePreference() { 212 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 213 when(mBluetoothDeviceUpdater. 214 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 215 when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true); 216 217 mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, 218 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); 219 220 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 221 } 222 223 @Test onProfileConnectionStateChanged_hfpDeviceConnected_notInCall_addPreference()224 public void onProfileConnectionStateChanged_hfpDeviceConnected_notInCall_addPreference() { 225 mAudioManager.setMode(AudioManager.MODE_NORMAL); 226 when(mBluetoothDeviceUpdater. 227 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 228 when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true); 229 230 mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, 231 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); 232 233 verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); 234 } 235 236 @Test onProfileConnectionStateChanged_ashaHearingAidConnected_inCall_removePreference()237 public void onProfileConnectionStateChanged_ashaHearingAidConnected_inCall_removePreference() 238 { 239 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 240 when(mBluetoothDeviceUpdater. 241 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 242 when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true); 243 244 mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, 245 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID); 246 247 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 248 } 249 250 @Test onProfileConnectionStateChanged_ashaHearingAidConnected_notInCall_removePreference()251 public void onProfileConnectionStateChanged_ashaHearingAidConnected_notInCall_removePreference() 252 { 253 mAudioManager.setMode(AudioManager.MODE_NORMAL); 254 when(mBluetoothDeviceUpdater. 255 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 256 when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true); 257 258 mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, 259 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID); 260 261 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 262 } 263 264 @Test onProfileConnectionStateChanged_leAudioDeviceConnected_inCall_removesPreference()265 public void onProfileConnectionStateChanged_leAudioDeviceConnected_inCall_removesPreference() { 266 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 267 when(mBluetoothDeviceUpdater 268 .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 269 when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true); 270 271 mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, 272 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO); 273 274 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 275 } 276 277 @Test onProfileConnectionStateChanged_leAudioDeviceConnected_notInCall_removesPreference()278 public void onProfileConnectionStateChanged_leAudioDeviceConnected_notInCall_removesPreference() 279 { 280 mAudioManager.setMode(AudioManager.MODE_NORMAL); 281 when(mBluetoothDeviceUpdater 282 .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 283 when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true); 284 285 mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, 286 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO); 287 288 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 289 } 290 @Test onProfileConnectionStateChanged_deviceIsNotInList_inCall_invokesRemovesPreference()291 public void onProfileConnectionStateChanged_deviceIsNotInList_inCall_invokesRemovesPreference() 292 { 293 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 294 when(mBluetoothDeviceUpdater 295 .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 296 when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true); 297 mCachedDevices.clear(); 298 299 mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, 300 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO); 301 302 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 303 } 304 305 @Test onProfileConnectionStateChanged_deviceIsNotInList_notInCall_invokesRemovesPreference()306 public void onProfileConnectionStateChanged_deviceIsNotInList_notInCall_invokesRemovesPreference 307 () { 308 mAudioManager.setMode(AudioManager.MODE_NORMAL); 309 when(mBluetoothDeviceUpdater 310 .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 311 when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true); 312 mCachedDevices.clear(); 313 314 mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, 315 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO); 316 317 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 318 } 319 320 @Test onProfileConnectionStateChanged_deviceDisconnected_removePreference()321 public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() { 322 mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, 323 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP); 324 325 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 326 } 327 328 @Test addPreference_addPreference_shouldHideSecondTarget()329 public void addPreference_addPreference_shouldHideSecondTarget() { 330 BluetoothDevicePreference btPreference = 331 new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, 332 true, BluetoothDevicePreference.SortType.TYPE_DEFAULT); 333 mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, btPreference); 334 335 mBluetoothDeviceUpdater.addPreference(mCachedBluetoothDevice); 336 337 assertThat(btPreference.shouldHideSecondTarget()).isTrue(); 338 } 339 340 @Test 341 @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) update_notExclusiveManagedDevice_addDevice()342 public void update_notExclusiveManagedDevice_addDevice() { 343 mAudioManager.setMode(AudioManager.MODE_NORMAL); 344 when(mBluetoothDeviceUpdater 345 .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 346 when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true); 347 when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( 348 null); 349 350 mBluetoothDeviceUpdater.update(mCachedBluetoothDevice); 351 352 verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); 353 } 354 355 @Test 356 @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) update_exclusivelyManagedDevice_packageNotInstalled_addDevice()357 public void update_exclusivelyManagedDevice_packageNotInstalled_addDevice() 358 throws Exception { 359 mAudioManager.setMode(AudioManager.MODE_NORMAL); 360 when(mBluetoothDeviceUpdater 361 .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 362 when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true); 363 when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( 364 TEST_EXCLUSIVE_MANAGER.getBytes()); 365 doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager) 366 .getApplicationInfo(TEST_EXCLUSIVE_MANAGER, 0); 367 368 mBluetoothDeviceUpdater.update(mCachedBluetoothDevice); 369 370 verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); 371 } 372 373 @Test 374 @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) update_exclusivelyManagedDevice_packageNotEnabled_addDevice()375 public void update_exclusivelyManagedDevice_packageNotEnabled_addDevice() 376 throws Exception { 377 ApplicationInfo appInfo = new ApplicationInfo(); 378 appInfo.enabled = false; 379 mAudioManager.setMode(AudioManager.MODE_NORMAL); 380 when(mBluetoothDeviceUpdater 381 .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 382 when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true); 383 when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( 384 TEST_EXCLUSIVE_MANAGER.getBytes()); 385 doReturn(appInfo).when(mPackageManager).getApplicationInfo(TEST_EXCLUSIVE_MANAGER, 0); 386 387 mBluetoothDeviceUpdater.update(mCachedBluetoothDevice); 388 389 verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); 390 } 391 392 @Test 393 @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) update_exclusivelyManagedDevice_packageInstalledAndEnabled_removePreference()394 public void update_exclusivelyManagedDevice_packageInstalledAndEnabled_removePreference() 395 throws Exception { 396 mAudioManager.setMode(AudioManager.MODE_NORMAL); 397 when(mBluetoothDeviceUpdater 398 .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); 399 when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true); 400 when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( 401 TEST_EXCLUSIVE_MANAGER.getBytes()); 402 doReturn(new ApplicationInfo()).when(mPackageManager).getApplicationInfo( 403 TEST_EXCLUSIVE_MANAGER, 0); 404 405 mBluetoothDeviceUpdater.update(mCachedBluetoothDevice); 406 407 verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); 408 verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice); 409 } 410 } 411