1 /* 2 * Copyright (C) 2018 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 17 package com.android.settings.sound; 18 19 import static android.media.AudioSystem.DEVICE_OUT_BLE_HEADSET; 20 import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; 21 import static android.media.AudioSystem.DEVICE_OUT_EARPIECE; 22 import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID; 23 24 import static com.android.settingslib.media.flags.Flags.FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING; 25 import static com.android.settingslib.flags.Flags.FLAG_ENABLE_LE_AUDIO_SHARING; 26 27 import static com.google.common.truth.Truth.assertThat; 28 29 import static org.mockito.ArgumentMatchers.any; 30 import static org.mockito.Mockito.doReturn; 31 import static org.mockito.Mockito.mock; 32 import static org.mockito.Mockito.never; 33 import static org.mockito.Mockito.spy; 34 import static org.mockito.Mockito.verify; 35 import static org.mockito.Mockito.when; 36 37 import android.bluetooth.BluetoothAdapter; 38 import android.bluetooth.BluetoothDevice; 39 import android.bluetooth.BluetoothLeBroadcast; 40 import android.bluetooth.BluetoothManager; 41 import android.content.Context; 42 import android.content.Intent; 43 import android.content.pm.ApplicationInfo; 44 import android.content.pm.PackageInfo; 45 import android.content.pm.PackageStats; 46 import android.media.AudioAttributes; 47 import android.media.AudioManager; 48 import android.media.VolumeProvider; 49 import android.media.session.MediaController; 50 import android.media.session.MediaSessionManager; 51 import android.media.session.PlaybackState; 52 import android.platform.test.flag.junit.SetFlagsRule; 53 54 import androidx.preference.Preference; 55 import androidx.preference.PreferenceManager; 56 import androidx.preference.PreferenceScreen; 57 58 import com.android.settings.R; 59 import com.android.settings.bluetooth.Utils; 60 import com.android.settings.testutils.shadow.ShadowAudioManager; 61 import com.android.settings.testutils.shadow.ShadowBluetoothUtils; 62 import com.android.settingslib.bluetooth.A2dpProfile; 63 import com.android.settingslib.bluetooth.BluetoothEventManager; 64 import com.android.settingslib.bluetooth.CachedBluetoothDevice; 65 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; 66 import com.android.settingslib.bluetooth.HearingAidProfile; 67 import com.android.settingslib.bluetooth.LeAudioProfile; 68 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; 69 import com.android.settingslib.bluetooth.LocalBluetoothManager; 70 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; 71 import com.android.settingslib.media.MediaOutputConstants; 72 73 import org.junit.After; 74 import org.junit.Before; 75 import org.junit.Rule; 76 import org.junit.Test; 77 import org.junit.runner.RunWith; 78 import org.mockito.ArgumentCaptor; 79 import org.mockito.Mock; 80 import org.mockito.MockitoAnnotations; 81 import org.robolectric.RobolectricTestRunner; 82 import org.robolectric.RuntimeEnvironment; 83 import org.robolectric.Shadows; 84 import org.robolectric.annotation.Config; 85 import org.robolectric.shadows.ShadowBluetoothDevice; 86 import org.robolectric.shadows.ShadowPackageManager; 87 88 import java.util.ArrayList; 89 import java.util.Collection; 90 import java.util.List; 91 92 @RunWith(RobolectricTestRunner.class) 93 @Config(shadows = { 94 ShadowAudioManager.class, 95 ShadowBluetoothUtils.class, 96 ShadowBluetoothDevice.class} 97 ) 98 public class MediaOutputPreferenceControllerTest { 99 private static final String TEST_KEY = "Test_Key"; 100 private static final String TEST_DEVICE_NAME_1 = "Test_A2DP_BT_Device_NAME_1"; 101 private static final String TEST_DEVICE_NAME_2 = "Test_A2DP_BT_Device_NAME_2"; 102 private static final String TEST_HAP_DEVICE_NAME_1 = "Test_HAP_BT_Device_NAME_1"; 103 private static final String TEST_HAP_DEVICE_NAME_2 = "Test_HAP_BT_Device_NAME_2"; 104 private static final String TEST_LE_AUDIO_DEVICE_NAME_1 = "Test_LE_AUDIO_Device_NAME_1"; 105 private static final String TEST_DEVICE_ADDRESS_1 = "00:A1:A1:A1:A1:A1"; 106 private static final String TEST_DEVICE_ADDRESS_2 = "00:B2:B2:B2:B2:B2"; 107 private static final String TEST_DEVICE_ADDRESS_3 = "00:C3:C3:C3:C3:C3"; 108 private static final String TEST_DEVICE_ADDRESS_4 = "00:D4:D4:D4:D4:D4"; 109 private static final String TEST_DEVICE_ADDRESS_5 = "00:E5:E5:E5:E5:E5"; 110 private static final String TEST_PACKAGE_NAME = "com.test.packagename"; 111 private static final String TEST_APPLICATION_LABEL = "APP Test Label"; 112 113 @Rule 114 public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 115 116 @Mock 117 private LocalBluetoothManager mLocalManager; 118 @Mock 119 private BluetoothEventManager mBluetoothEventManager; 120 @Mock 121 private LocalBluetoothProfileManager mLocalBluetoothProfileManager; 122 @Mock 123 private A2dpProfile mA2dpProfile; 124 @Mock 125 private HearingAidProfile mHearingAidProfile; 126 @Mock 127 private LeAudioProfile mLeAudioProfile; 128 @Mock 129 private LocalBluetoothLeBroadcast mLocalBluetoothLeBroadcast; 130 @Mock 131 private AudioSwitchPreferenceController.AudioSwitchCallback mAudioSwitchPreferenceCallback; 132 @Mock 133 private MediaSessionManager mMediaSessionManager; 134 @Mock 135 private MediaController mMediaController; 136 @Mock 137 private CachedBluetoothDeviceManager mCachedDeviceManager; 138 @Mock 139 private CachedBluetoothDevice mCachedBluetoothDeviceL; 140 @Mock 141 private CachedBluetoothDevice mCachedBluetoothDeviceR; 142 143 private Context mContext; 144 private PreferenceScreen mScreen; 145 private Preference mPreference; 146 private AudioManager mAudioManager; 147 private ShadowAudioManager mShadowAudioManager; 148 private BluetoothManager mBluetoothManager; 149 private BluetoothAdapter mBluetoothAdapter; 150 private BluetoothDevice mBluetoothDevice; 151 private BluetoothDevice mSecondBluetoothDevice; 152 private BluetoothDevice mLeftBluetoothHapDevice; 153 private BluetoothDevice mRightBluetoothHapDevice; 154 private LocalBluetoothManager mLocalBluetoothManager; 155 private MediaOutputPreferenceController mController; 156 private List<BluetoothDevice> mProfileConnectedDevices; 157 private List<BluetoothDevice> mHearingAidActiveDevices; 158 private List<BluetoothDevice> mLeAudioActiveDevices; 159 private List<MediaController> mMediaControllers = new ArrayList<>(); 160 private MediaController.PlaybackInfo mPlaybackInfo; 161 private PlaybackState mPlaybackState; 162 private ShadowPackageManager mShadowPackageManager; 163 private ApplicationInfo mAppInfo; 164 private PackageInfo mPackageInfo; 165 private PackageStats mPackageStats; 166 private Collection<CachedBluetoothDevice> mCachedDevices; 167 168 @Before setUp()169 public void setUp() { 170 MockitoAnnotations.initMocks(this); 171 mContext = spy(RuntimeEnvironment.application); 172 173 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 174 mShadowAudioManager = ShadowAudioManager.getShadow(); 175 176 ShadowBluetoothUtils.sLocalBluetoothManager = mLocalManager; 177 mLocalBluetoothManager = Utils.getLocalBtManager(mContext); 178 179 doReturn(mMediaSessionManager).when(mContext).getSystemService(MediaSessionManager.class); 180 when(mMediaSessionManager.getActiveSessions(any())).thenReturn(mMediaControllers); 181 when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME); 182 mPlaybackInfo = new MediaController.PlaybackInfo( 183 MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL, 184 VolumeProvider.VOLUME_CONTROL_ABSOLUTE, 185 100, 186 10, 187 new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(), 188 null); 189 mPlaybackState = new PlaybackState.Builder() 190 .setState(PlaybackState.STATE_PLAYING, 0, 1) 191 .build(); 192 when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo); 193 when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState); 194 mMediaControllers.add(mMediaController); 195 196 when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager); 197 when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager); 198 when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); 199 when(mLocalBluetoothProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile); 200 when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); 201 when(mLocalBluetoothProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile); 202 when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()) 203 .thenReturn(mLocalBluetoothLeBroadcast); 204 205 mBluetoothManager = mContext.getSystemService(BluetoothManager.class); 206 mBluetoothAdapter = mBluetoothManager.getAdapter(); 207 208 mCachedDevices = new ArrayList<>(); 209 mCachedDevices.add(mCachedBluetoothDeviceL); 210 mCachedDevices.add(mCachedBluetoothDeviceR); 211 when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices); 212 213 mBluetoothDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_1)); 214 when(mBluetoothDevice.getName()).thenReturn(TEST_DEVICE_NAME_1); 215 when(mBluetoothDevice.getAlias()).thenReturn(TEST_DEVICE_NAME_1); 216 when(mBluetoothDevice.isConnected()).thenReturn(true); 217 218 mSecondBluetoothDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2)); 219 when(mSecondBluetoothDevice.getName()).thenReturn(TEST_DEVICE_NAME_2); 220 when(mSecondBluetoothDevice.isConnected()).thenReturn(true); 221 222 mLeftBluetoothHapDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_3)); 223 when(mLeftBluetoothHapDevice.getName()).thenReturn(TEST_HAP_DEVICE_NAME_1); 224 when(mLeftBluetoothHapDevice.getAlias()).thenReturn(TEST_HAP_DEVICE_NAME_1); 225 when(mLeftBluetoothHapDevice.isConnected()).thenReturn(true); 226 227 mRightBluetoothHapDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_4)); 228 when(mRightBluetoothHapDevice.getName()).thenReturn(TEST_HAP_DEVICE_NAME_2); 229 when(mRightBluetoothHapDevice.isConnected()).thenReturn(true); 230 231 mController = new MediaOutputPreferenceController(mContext, TEST_KEY); 232 mScreen = spy(new PreferenceScreen(mContext, null)); 233 mPreference = new Preference(mContext); 234 mProfileConnectedDevices = new ArrayList<>(); 235 mHearingAidActiveDevices = new ArrayList<>(2); 236 mLeAudioActiveDevices = new ArrayList<>(); 237 238 when(mScreen.getPreferenceManager()).thenReturn(mock(PreferenceManager.class)); 239 when(mScreen.getContext()).thenReturn(mContext); 240 when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); 241 mScreen.addPreference(mPreference); 242 mController.displayPreference(mScreen); 243 mController.setCallback(mAudioSwitchPreferenceCallback); 244 } 245 246 @After tearDown()247 public void tearDown() { 248 ShadowBluetoothUtils.reset(); 249 } 250 251 /** Device start broadcasting so Preference summary should become "Audio Sharing" */ 252 @Test audioSharingStart_changeSummary()253 public void audioSharingStart_changeSummary() { 254 mSetFlagsRule.enableFlags(FLAG_ENABLE_LE_AUDIO_SHARING); 255 mController.onStart(); 256 ArgumentCaptor<BluetoothLeBroadcast.Callback> broadcastCallbackCaptor = 257 ArgumentCaptor.forClass(BluetoothLeBroadcast.Callback.class); 258 mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP); 259 mAudioManager.setMode(AudioManager.MODE_NORMAL); 260 when(mLocalBluetoothLeBroadcast.isEnabled(null)).thenReturn(true); 261 verify(mLocalBluetoothLeBroadcast) 262 .registerServiceCallBack(any(), broadcastCallbackCaptor.capture()); 263 BluetoothLeBroadcast.Callback callback = broadcastCallbackCaptor.getValue(); 264 265 callback.onBroadcastStarted(0, 0); 266 assertThat(mPreference.getSummary().toString()) 267 .isEqualTo(mContext.getText(R.string.media_output_audio_sharing).toString()); 268 } 269 270 /** 271 * A2DP Bluetooth device(s) are connected, but no device is set as activated 272 * Preference summary should be "This device" 273 */ 274 @Test updateState_withConnectedBtDevice_withoutActiveBtDevice_setDefaultSummary()275 public void updateState_withConnectedBtDevice_withoutActiveBtDevice_setDefaultSummary() { 276 mShadowAudioManager.setOutputDevice(DEVICE_OUT_EARPIECE); 277 mAudioManager.setMode(AudioManager.MODE_NORMAL); 278 mProfileConnectedDevices.clear(); 279 mProfileConnectedDevices.add(mBluetoothDevice); 280 mProfileConnectedDevices.add(mSecondBluetoothDevice); 281 when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices); 282 when(mA2dpProfile.getActiveDevice()).thenReturn(null); 283 284 assertThat(mPreference.getSummary()).isNull(); 285 mController.updateState(mPreference); 286 assertThat(mPreference.getSummary()).isEqualTo( 287 mContext.getText(R.string.media_output_default_summary)); 288 } 289 290 /** 291 * A2DP Bluetooth device(s) are connected and active 292 * Preference summary should be device's name 293 */ 294 @Test updateState_withActiveBtDevice_setActivatedDeviceName()295 public void updateState_withActiveBtDevice_setActivatedDeviceName() { 296 mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP); 297 mAudioManager.setMode(AudioManager.MODE_NORMAL); 298 mProfileConnectedDevices.clear(); 299 mProfileConnectedDevices.add(mBluetoothDevice); 300 mProfileConnectedDevices.add(mSecondBluetoothDevice); 301 when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices); 302 when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice); 303 304 assertThat(mPreference.getSummary()).isNull(); 305 mController.updateState(mPreference); 306 assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1); 307 } 308 309 /** 310 * Hearing Aid device(s) are connected and active 311 * Preference summary should be device's name 312 */ 313 @Test updateState_withActiveHADevice_setActivatedDeviceName()314 public void updateState_withActiveHADevice_setActivatedDeviceName() { 315 mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID); 316 mAudioManager.setMode(AudioManager.MODE_NORMAL); 317 mHearingAidActiveDevices.clear(); 318 mHearingAidActiveDevices.add(mLeftBluetoothHapDevice); 319 when(mHearingAidProfile.getConnectedDevices()).thenReturn(mHearingAidActiveDevices); 320 when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices); 321 322 assertThat(mPreference.getSummary()).isNull(); 323 mController.updateState(mPreference); 324 assertThat(mPreference.getSummary()).isEqualTo(TEST_HAP_DEVICE_NAME_1); 325 326 } 327 328 @Test updateState_withActiveLeAudioDevice_setActivatedDeviceName()329 public void updateState_withActiveLeAudioDevice_setActivatedDeviceName() { 330 mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLE_HEADSET); 331 mAudioManager.setMode(AudioManager.MODE_NORMAL); 332 when(mCachedBluetoothDeviceL.getDevice()).thenReturn(mBluetoothDevice); 333 when(mCachedBluetoothDeviceR.getDevice()).thenReturn(mSecondBluetoothDevice); 334 when(mBluetoothDevice.getAlias()).thenReturn(TEST_LE_AUDIO_DEVICE_NAME_1); 335 mProfileConnectedDevices.clear(); 336 mProfileConnectedDevices.add(mBluetoothDevice); 337 mProfileConnectedDevices.add(mSecondBluetoothDevice); 338 mLeAudioActiveDevices.clear(); 339 mLeAudioActiveDevices.add(mBluetoothDevice); 340 when(mLeAudioProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices); 341 when(mLeAudioProfile.getActiveDevices()).thenReturn(mLeAudioActiveDevices); 342 343 assertThat(mPreference.getSummary()).isNull(); 344 mController.updateState(mPreference); 345 assertThat(mPreference.getSummary()).isEqualTo(TEST_LE_AUDIO_DEVICE_NAME_1); 346 } 347 348 @Test updateState_noActiveLocalPlayback_noTitle()349 public void updateState_noActiveLocalPlayback_noTitle() { 350 mSetFlagsRule.disableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); 351 mPlaybackState = new PlaybackState.Builder() 352 .setState(PlaybackState.STATE_NONE, 0, 1) 353 .build(); 354 when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState); 355 mController = new MediaOutputPreferenceController(mContext, TEST_KEY); 356 357 mController.updateState(mPreference); 358 359 assertThat(mPreference.getTitle()).isNull(); 360 } 361 362 @Test updateState_noActiveLocalPlayback_checkTitle()363 public void updateState_noActiveLocalPlayback_checkTitle() { 364 mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); 365 mPlaybackState = new PlaybackState.Builder() 366 .setState(PlaybackState.STATE_NONE, 0, 1) 367 .build(); 368 when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState); 369 mController = new MediaOutputPreferenceController(mContext, TEST_KEY); 370 mController.displayPreference(mScreen); 371 372 mController.updateState(mPreference); 373 374 assertThat(mPreference.getTitle().toString()).isEqualTo( 375 mContext.getString(R.string.media_output_title_without_playing, 376 TEST_APPLICATION_LABEL)); 377 } 378 379 @Test updateState_withNullMediaController_noTitle()380 public void updateState_withNullMediaController_noTitle() { 381 mSetFlagsRule.disableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); 382 mMediaControllers.clear(); 383 mController = new MediaOutputPreferenceController(mContext, TEST_KEY); 384 385 mController.updateState(mPreference); 386 387 assertThat(mPreference.getTitle()).isNull(); 388 } 389 390 @Test updateState_withNullMediaController_checkTitle()391 public void updateState_withNullMediaController_checkTitle() { 392 mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); 393 mMediaControllers.clear(); 394 mController = new MediaOutputPreferenceController(mContext, TEST_KEY); 395 mController.displayPreference(mScreen); 396 397 mController.updateState(mPreference); 398 399 assertThat(mPreference.getTitle().toString()).isEqualTo( 400 mContext.getString(R.string.media_output_title_without_playing, 401 TEST_APPLICATION_LABEL)); 402 } 403 404 @Test updateState_withActiveLocalPlayback_checkTitle()405 public void updateState_withActiveLocalPlayback_checkTitle() { 406 initPackage(); 407 mShadowPackageManager.addPackage(mPackageInfo, mPackageStats); 408 409 mController.updateState(mPreference); 410 411 assertThat(mPreference.getTitle()).isEqualTo( 412 mContext.getString(R.string.media_output_label_title, TEST_APPLICATION_LABEL)); 413 } 414 415 @Test click_launch_outputSwitcherSlice()416 public void click_launch_outputSwitcherSlice() { 417 final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 418 mController.handlePreferenceTreeClick(mPreference); 419 verify(mContext, never()).startActivity(intentCaptor.capture()); 420 421 mPreference.setKey(TEST_KEY); 422 mController.handlePreferenceTreeClick(mPreference); 423 verify(mContext).sendBroadcast(intentCaptor.capture()); 424 assertThat(intentCaptor.getValue().getAction()) 425 .isEqualTo(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG); 426 } 427 428 @Test handlePreferenceTreeClick_WithNoLocalPlaybackFlagEnabled_verifyIntentExtra()429 public void handlePreferenceTreeClick_WithNoLocalPlaybackFlagEnabled_verifyIntentExtra() { 430 mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); 431 final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 432 mPlaybackState = new PlaybackState.Builder() 433 .setState(PlaybackState.STATE_NONE, 0, 1) 434 .build(); 435 when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState); 436 mController = new MediaOutputPreferenceController(mContext, TEST_KEY); 437 mPreference.setKey(TEST_KEY); 438 439 mController.handlePreferenceTreeClick(mPreference); 440 441 verify(mContext).sendBroadcast(intentCaptor.capture()); 442 assertThat(intentCaptor.getValue().getAction()) 443 .isEqualTo(MediaOutputConstants.ACTION_LAUNCH_SYSTEM_MEDIA_OUTPUT_DIALOG); 444 } 445 446 @Test handlePreferenceTreeClick_WithNullControllerFlagEnabled_verifyIntentExtra()447 public void handlePreferenceTreeClick_WithNullControllerFlagEnabled_verifyIntentExtra() { 448 mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); 449 final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 450 mMediaControllers.clear(); 451 mController = new MediaOutputPreferenceController(mContext, TEST_KEY); 452 mPreference.setKey(TEST_KEY); 453 454 mController.handlePreferenceTreeClick(mPreference); 455 456 verify(mContext).sendBroadcast(intentCaptor.capture()); 457 assertThat(intentCaptor.getValue().getAction()) 458 .isEqualTo(MediaOutputConstants.ACTION_LAUNCH_SYSTEM_MEDIA_OUTPUT_DIALOG); 459 } 460 461 /** 462 * Default status 463 * Preference should be invisible 464 * Summary should be default summary 465 */ 466 @Test updateState_notInCall_preferenceVisible()467 public void updateState_notInCall_preferenceVisible() { 468 mAudioManager.setMode(AudioManager.MODE_NORMAL); 469 470 mController.updateState(mPreference); 471 472 assertThat(mPreference.isVisible()).isTrue(); 473 } 474 475 /** 476 * During a call 477 * Preference should be invisible 478 * Default string should be "Unavailable during calls" 479 */ 480 @Test updateState_inCall_preferenceInvisible()481 public void updateState_inCall_preferenceInvisible() { 482 mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); 483 484 mController.updateState(mPreference); 485 486 assertThat(mPreference.isVisible()).isFalse(); 487 } 488 489 @Test findActiveDevice_onlyA2dpDeviceActive_returnA2dpDevice()490 public void findActiveDevice_onlyA2dpDeviceActive_returnA2dpDevice() { 491 when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(null); 492 when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice); 493 494 assertThat(mController.findActiveDevice()).isEqualTo(mBluetoothDevice); 495 } 496 497 @Test findActiveDevice_allDevicesNotActive_returnNull()498 public void findActiveDevice_allDevicesNotActive_returnNull() { 499 when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(null); 500 when(mA2dpProfile.getActiveDevice()).thenReturn(null); 501 502 assertThat(mController.findActiveDevice()).isNull(); 503 } 504 505 @Test findActiveDevice_allProfilesWithActiveDevice_returnHADevice()506 public void findActiveDevice_allProfilesWithActiveDevice_returnHADevice() { 507 BluetoothDevice btLeDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_5)); 508 when(btLeDevice.getName()).thenReturn(TEST_LE_AUDIO_DEVICE_NAME_1); 509 mLeAudioActiveDevices.clear(); 510 mLeAudioActiveDevices.add(btLeDevice); 511 mHearingAidActiveDevices.clear(); 512 mHearingAidActiveDevices.add(mLeftBluetoothHapDevice); 513 when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices); 514 when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice); 515 when(mLeAudioProfile.getActiveDevices()).thenReturn(mLeAudioActiveDevices); 516 517 assertThat(mController.findActiveDevice()).isEqualTo(mLeftBluetoothHapDevice); 518 } 519 520 @Test findActiveDevice_a2dpDeviceAndLeAudioDeviceActive_returnLeAudioDevice()521 public void findActiveDevice_a2dpDeviceAndLeAudioDeviceActive_returnLeAudioDevice() { 522 BluetoothDevice btLeDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_5)); 523 when(btLeDevice.getName()).thenReturn(TEST_LE_AUDIO_DEVICE_NAME_1); 524 mLeAudioActiveDevices.clear(); 525 mLeAudioActiveDevices.add(btLeDevice); 526 mHearingAidActiveDevices.clear(); 527 when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices); 528 when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice); 529 when(mLeAudioProfile.getActiveDevices()).thenReturn(mLeAudioActiveDevices); 530 531 assertThat(mController.findActiveDevice()).isEqualTo(btLeDevice); 532 } 533 534 @Test findActiveDevice_onlyLeAudioDeviceActive_returnLeAudioDevice()535 public void findActiveDevice_onlyLeAudioDeviceActive_returnLeAudioDevice() { 536 BluetoothDevice btLeDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_5)); 537 when(btLeDevice.getName()).thenReturn(TEST_LE_AUDIO_DEVICE_NAME_1); 538 mLeAudioActiveDevices.clear(); 539 mLeAudioActiveDevices.add(btLeDevice); 540 mHearingAidActiveDevices.clear(); 541 when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices); 542 when(mA2dpProfile.getActiveDevice()).thenReturn(null); 543 when(mLeAudioProfile.getActiveDevices()).thenReturn(mLeAudioActiveDevices); 544 545 assertThat(mController.findActiveDevice()).isEqualTo(btLeDevice); 546 } 547 initPackage()548 private void initPackage() { 549 mShadowPackageManager = Shadows.shadowOf(mContext.getPackageManager()); 550 mAppInfo = new ApplicationInfo(); 551 mAppInfo.flags = ApplicationInfo.FLAG_INSTALLED; 552 mAppInfo.packageName = TEST_PACKAGE_NAME; 553 mAppInfo.name = TEST_APPLICATION_LABEL; 554 mPackageInfo = new PackageInfo(); 555 mPackageInfo.packageName = TEST_PACKAGE_NAME; 556 mPackageInfo.applicationInfo = mAppInfo; 557 mPackageStats = new PackageStats(TEST_PACKAGE_NAME); 558 } 559 } 560