From 9f407aba369f2699c3d2bb8d2879b2103afcb577 Mon Sep 17 00:00:00 2001 From: ryanywlin Date: Fri, 27 Apr 2018 16:54:43 +0800 Subject: [PATCH] Find active device for add hearing aids device into audio switcher. - Find active device accroding to different stream type and output device. - update isStreamFromOutputDevice() to identify general case like DEVICE_OUT_BLUETOOTH_A2DP is subset of DEVICE_OUT_ALL_A2DP. - add test case for these methods. Bug: 78142719 Test: make RunSettingsRoboTests ROBOTEST_FILTER="AudioOutputSwitchPreferenceControllerTest" -j28 Change-Id: I381135c120dbf051679bff7626d47e41f8d589da --- .../AudioSwitchPreferenceController.java | 36 ++++- ...oOutputSwitchPreferenceControllerTest.java | 150 ++++++++++++++++++ 2 files changed, 185 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java index 43cd29f5e28..ea7e8fed768 100644 --- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java +++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java @@ -203,7 +203,7 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont } protected boolean isStreamFromOutputDevice(int streamType, int device) { - return mAudioManager.getDevicesForStream(streamType) == device; + return (device & mAudioManager.getDevicesForStream(streamType)) != 0; } protected boolean isOngoingCallStatus() { @@ -272,6 +272,40 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont return connectedDevices; } + /** + * According to different stream and output device, find the active device from + * the corresponding profile. Hearing aid device could stream both STREAM_MUSIC + * and STREAM_VOICE_CALL. + * + * @param streamType the type of audio streams. + * @return the active device. Return null if the active device is current device + * or streamType is not STREAM_MUSIC or STREAM_VOICE_CALL. + */ + protected BluetoothDevice findActiveDevice(int streamType) { + if (streamType != STREAM_MUSIC && streamType != STREAM_VOICE_CALL) { + return null; + } + if (isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_ALL_A2DP)) { + return mProfileManager.getA2dpProfile().getActiveDevice(); + } else if (isStreamFromOutputDevice(STREAM_VOICE_CALL, DEVICE_OUT_ALL_SCO)) { + return mProfileManager.getHeadsetProfile().getActiveDevice(); + } else if (isStreamFromOutputDevice(streamType, DEVICE_OUT_HEARING_AID)) { + // The first element is the left active device; the second element is + // the right active device. And they will have same hiSyncId. If either + // or both side is not active, it will be null on that position. + List activeDevices = + mProfileManager.getHearingAidProfile().getActiveDevices(); + for (BluetoothDevice btDevice : activeDevices) { + if (btDevice != null && mConnectedDevices.contains(btDevice)) { + // also need to check mConnectedDevices, because one of + // the device(same hiSyncId) might not be shown in the UI. + return btDevice; + } + } + } + return null; + } + int getDefaultDeviceIndex() { // Default device is after all connected devices. return ArrayUtils.size(mConnectedDevices); diff --git a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java index df652975ad8..61b9180eb33 100644 --- a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java @@ -17,6 +17,15 @@ package com.android.settings.sound; +import static android.media.AudioManager.DEVICE_OUT_BLUETOOTH_SCO; +import static android.media.AudioManager.STREAM_RING; +import static android.media.AudioManager.STREAM_VOICE_CALL; +import static android.media.AudioSystem.DEVICE_OUT_ALL_SCO; +import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; +import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; +import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID; +import static android.media.AudioSystem.STREAM_MUSIC; + import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; @@ -253,6 +262,147 @@ public class AudioOutputSwitchPreferenceControllerTest { assertThat(mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1)).isFalse(); } + /** + * Audio stream output to bluetooth sco headset which is the subset of all sco device. + * isStreamFromOutputDevice should return true. + */ + @Test + public void isStreamFromOutputDevice_outputDeviceIsBtScoHeadset_shouldReturnTrue() { + mShadowAudioManager.setStream(DEVICE_OUT_BLUETOOTH_SCO_HEADSET); + + assertThat(mController.isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_ALL_SCO)).isTrue(); + } + + /** + * Audio stream is not STREAM_MUSIC or STREAM_VOICE_CALL. + * findActiveDevice should return null. + */ + @Test + public void findActiveDevice_streamIsRing_shouldReturnNull() { + assertThat(mController.findActiveDevice(STREAM_RING)).isNull(); + } + + /** + * Audio stream is STREAM_MUSIC and output device is A2dp bluetooth device. + * findActiveDevice should return A2dp active device. + */ + @Test + public void findActiveDevice_streamMusicToA2dpDevice_shouldReturnActiveA2dpDevice() { + mShadowAudioManager.setStream(DEVICE_OUT_BLUETOOTH_A2DP); + mHearingAidActiveDevices.clear(); + mHearingAidActiveDevices.add(mBluetoothHapDevice); + when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothHapDevice); + when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice); + when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices); + + assertThat(mController.findActiveDevice(STREAM_MUSIC)).isEqualTo(mBluetoothDevice); + } + + /** + * Audio stream is STREAM_VOICE_CALL and output device is Hands free profile bluetooth device. + * findActiveDevice should return Hands free profile active device. + */ + @Test + public void findActiveDevice_streamVoiceCallToHfpDevice_shouldReturnActiveHfpDevice() { + mShadowAudioManager.setStream(DEVICE_OUT_BLUETOOTH_SCO); + mHearingAidActiveDevices.clear(); + mHearingAidActiveDevices.add(mBluetoothHapDevice); + when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice); + when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothHapDevice); + when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices); + + assertThat(mController.findActiveDevice(STREAM_VOICE_CALL)).isEqualTo(mBluetoothDevice); + } + + /** + * Audio stream is STREAM_MUSIC or STREAM_VOICE_CALL and output device is hearing aid profile + * bluetooth device. And left side of HAP device is active. + * findActiveDevice should return hearing aid device active device. + */ + @Test + public void findActiveDevice_streamToHapDeviceLeftActiveDevice_shouldReturnActiveHapDevice() { + mShadowAudioManager.setStream(DEVICE_OUT_HEARING_AID); + mConnectedDevices.clear(); + mConnectedDevices.add(mBluetoothDevice); + mConnectedDevices.add(mBluetoothHapDevice); + mHearingAidActiveDevices.clear(); + mHearingAidActiveDevices.add(mBluetoothHapDevice); + mController.mConnectedDevices = mConnectedDevices; + when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice); + when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice); + when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices); + + assertThat(mController.findActiveDevice(STREAM_MUSIC)).isEqualTo(mBluetoothHapDevice); + assertThat(mController.findActiveDevice(STREAM_VOICE_CALL)).isEqualTo(mBluetoothHapDevice); + } + + /** + * Audio stream is STREAM_MUSIC or STREAM_VOICE_CALL and output device is hearing aid profile + * bluetooth device. And right side of HAP device is active. + * findActiveDevice should return hearing aid device active device. + */ + @Test + public void findActiveDevice_streamToHapDeviceRightActiveDevice_shouldReturnActiveHapDevice() { + mShadowAudioManager.setStream(DEVICE_OUT_HEARING_AID); + mConnectedDevices.clear(); + mConnectedDevices.add(mBluetoothDevice); + mConnectedDevices.add(mBluetoothHapDevice); + mHearingAidActiveDevices.clear(); + mHearingAidActiveDevices.add(null); + mHearingAidActiveDevices.add(mBluetoothHapDevice); + mController.mConnectedDevices = mConnectedDevices; + when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice); + when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice); + when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices); + + assertThat(mController.findActiveDevice(STREAM_MUSIC)).isEqualTo(mBluetoothHapDevice); + assertThat(mController.findActiveDevice(STREAM_VOICE_CALL)).isEqualTo(mBluetoothHapDevice); + } + + /** + * Audio stream is STREAM_MUSIC or STREAM_VOICE_CALL and output device is hearing aid + * profile bluetooth device. And both are active device. + * findActiveDevice should return only return the active device in mConnectedDevices. + */ + @Test + public void findActiveDevice_streamToHapDeviceTwoActiveDevice_shouldReturnActiveHapDevice() { + mShadowAudioManager.setStream(DEVICE_OUT_HEARING_AID); + mConnectedDevices.clear(); + mConnectedDevices.add(mBluetoothDevice); + mConnectedDevices.add(mBluetoothHapDevice); + mHearingAidActiveDevices.clear(); + mHearingAidActiveDevices.add(mSecondBluetoothHapDevice); + mHearingAidActiveDevices.add(mBluetoothHapDevice); + mController.mConnectedDevices = mConnectedDevices; + when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice); + when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice); + when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices); + + assertThat(mController.findActiveDevice(STREAM_MUSIC)).isEqualTo(mBluetoothHapDevice); + assertThat(mController.findActiveDevice(STREAM_VOICE_CALL)).isEqualTo(mBluetoothHapDevice); + } + + /** + * Audio stream is STREAM_MUSIC or STREAM_VOICE_CALL and output device is hearing aid + * profile bluetooth device. And none of them are active. + * findActiveDevice should return null. + */ + @Test + public void findActiveDevice_streamToOtherDevice_shouldReturnActiveHapDevice() { + mShadowAudioManager.setStream(DEVICE_OUT_HEARING_AID); + mConnectedDevices.clear(); + mConnectedDevices.add(mBluetoothDevice); + mConnectedDevices.add(mBluetoothHapDevice); + mHearingAidActiveDevices.clear(); + mController.mConnectedDevices = mConnectedDevices; + when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice); + when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice); + when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices); + + assertThat(mController.findActiveDevice(STREAM_MUSIC)).isNull(); + assertThat(mController.findActiveDevice(STREAM_VOICE_CALL)).isNull(); + } + /** * Two hearing aid devices with different HisyncId * getConnectedHearingAidDevices should add both device to list.