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