Loading packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java +4 −0 Original line number Diff line number Diff line Loading @@ -80,6 +80,10 @@ public class InputMediaDevice extends MediaDevice { context, id, audioDeviceInfoType, maxVolume, currentVolume, isVolumeFixed); } public @AudioDeviceType int getAudioDeviceInfoType() { return mAudioDeviceInfoType; } public static boolean isSupportedInputDevice(@AudioDeviceType int audioDeviceInfoType) { return switch (audioDeviceInfoType) { case TYPE_BUILTIN_MIC, Loading packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java +37 −1 Original line number Diff line number Diff line Loading @@ -15,13 +15,20 @@ */ package com.android.settingslib.media; import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED; import android.content.Context; import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceCallback; import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.media.MediaRecorder; import android.os.Handler; import android.util.Slog; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; Loading @@ -35,12 +42,18 @@ public final class InputRouteManager { private static final String TAG = "InputRouteManager"; @VisibleForTesting static final AudioAttributes INPUT_ATTRIBUTES = new AudioAttributes.Builder().setCapturePreset(MediaRecorder.AudioSource.MIC).build(); private final Context mContext; private final AudioManager mAudioManager; @VisibleForTesting final List<MediaDevice> mInputMediaDevices = new CopyOnWriteArrayList<>(); private MediaDevice mSelectedInputDevice; private final Collection<InputDeviceCallback> mCallbacks = new CopyOnWriteArrayList<>(); @VisibleForTesting Loading Loading @@ -76,8 +89,27 @@ public final class InputRouteManager { mCallbacks.remove(callback); } public @Nullable MediaDevice getSelectedInputDevice() { return mSelectedInputDevice; } private void dispatchInputDeviceListUpdate() { // TODO (b/360175574): Get selected input device. // Get selected input device. List<AudioDeviceAttributes> attributesOfSelectedInputDevices = mAudioManager.getDevicesForAttributes(INPUT_ATTRIBUTES); int selectedInputDeviceAttributesType; if (attributesOfSelectedInputDevices.isEmpty()) { Slog.e(TAG, "Unexpected empty list of input devices. Using built-in mic."); selectedInputDeviceAttributesType = AudioDeviceInfo.TYPE_BUILTIN_MIC; } else { if (attributesOfSelectedInputDevices.size() > 1) { Slog.w( TAG, "AudioManager.getDevicesForAttributes returned more than one element." + " Using the first one."); } selectedInputDeviceAttributesType = attributesOfSelectedInputDevices.get(0).getType(); } // Get all input devices. AudioDeviceInfo[] audioDeviceInfos = Loading @@ -93,6 +125,10 @@ public final class InputRouteManager { getCurrentInputGain(), isInputGainFixed()); if (mediaDevice != null) { if (info.getType() == selectedInputDeviceAttributesType) { mediaDevice.setState(STATE_SELECTED); mSelectedInputDevice = mediaDevice; } mInputMediaDevices.add(mediaDevice); } } Loading packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java +98 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.settingslib.media; import static com.android.settingslib.media.InputRouteManager.INPUT_ATTRIBUTES; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; Loading @@ -23,6 +25,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; import android.media.AudioManager; Loading @@ -36,6 +39,10 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.Collections; import java.util.List; @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowRouter2Manager.class}) public class InputRouteManagerTest { Loading Loading @@ -123,6 +130,97 @@ public class InputRouteManagerTest { assertThat(inputRouteManager.mInputMediaDevices).isEmpty(); } @Test public void getSelectedInputDevice_returnOneFromAudioManager() { final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class); when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET); when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID); final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class); when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC); when(info2.getId()).thenReturn(BUILTIN_MIC_ID); final AudioManager audioManager = mock(AudioManager.class); AudioDeviceInfo[] devices = {info1, info2}; when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices); // Mock audioManager.getDevicesForAttributes returns exactly one audioDeviceAttributes. AudioDeviceAttributes audioDeviceAttributes = new AudioDeviceAttributes(info1); when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES)) .thenReturn(Collections.singletonList(audioDeviceAttributes)); InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices); // The selected input device has the same type as the one returned from AudioManager. InputMediaDevice selectedInputDevice = (InputMediaDevice) inputRouteManager.getSelectedInputDevice(); assertThat(selectedInputDevice.getAudioDeviceInfoType()) .isEqualTo(AudioDeviceInfo.TYPE_WIRED_HEADSET); } @Test public void getSelectedInputDevice_returnMoreThanOneFromAudioManager() { final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class); when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET); when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID); final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class); when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC); when(info2.getId()).thenReturn(BUILTIN_MIC_ID); final AudioManager audioManager = mock(AudioManager.class); AudioDeviceInfo[] devices = {info1, info2}; when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices); // Mock audioManager.getDevicesForAttributes returns more than one audioDeviceAttributes. AudioDeviceAttributes audioDeviceAttributes1 = new AudioDeviceAttributes(info1); AudioDeviceAttributes audioDeviceAttributes2 = new AudioDeviceAttributes(info2); List<AudioDeviceAttributes> attributesOfSelectedInputDevices = new ArrayList<>(); attributesOfSelectedInputDevices.add(audioDeviceAttributes1); attributesOfSelectedInputDevices.add(audioDeviceAttributes2); when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES)) .thenReturn(attributesOfSelectedInputDevices); InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices); // The selected input device has the same type as the first one returned from AudioManager. InputMediaDevice selectedInputDevice = (InputMediaDevice) inputRouteManager.getSelectedInputDevice(); assertThat(selectedInputDevice.getAudioDeviceInfoType()) .isEqualTo(AudioDeviceInfo.TYPE_WIRED_HEADSET); } @Test public void getSelectedInputDevice_returnEmptyFromAudioManager() { final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class); when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET); when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID); final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class); when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC); when(info2.getId()).thenReturn(BUILTIN_MIC_ID); final AudioManager audioManager = mock(AudioManager.class); AudioDeviceInfo[] devices = {info1, info2}; when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices); // Mock audioManager.getDevicesForAttributes returns empty list of audioDeviceAttributes. List<AudioDeviceAttributes> attributesOfSelectedInputDevices = new ArrayList<>(); when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES)) .thenReturn(attributesOfSelectedInputDevices); InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices); // The selected input device has default type AudioDeviceInfo.TYPE_BUILTIN_MIC. InputMediaDevice selectedInputDevice = (InputMediaDevice) inputRouteManager.getSelectedInputDevice(); assertThat(selectedInputDevice.getAudioDeviceInfoType()) .isEqualTo(AudioDeviceInfo.TYPE_BUILTIN_MIC); } @Test public void getMaxInputGain_returnMaxInputGain() { assertThat(mInputRouteManager.getMaxInputGain()).isEqualTo(15); Loading packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java +13 −2 Original line number Diff line number Diff line Loading @@ -157,7 +157,7 @@ public class MediaSwitchingController @VisibleForTesting boolean mNeedRefresh = false; private MediaController mMediaController; private InputRouteManager mInputRouteManager; @VisibleForTesting InputRouteManager mInputRouteManager; @VisibleForTesting Callback mCallback; @VisibleForTesting Loading Loading @@ -927,9 +927,20 @@ public class MediaSwitchingController } public List<MediaDevice> getSelectedMediaDevice() { if (!enableInputRouting()) { return mLocalMediaManager.getSelectedMediaDevice(); } // Add selected input device if input routing is supported. List<MediaDevice> selectedDevices = new ArrayList<>(mLocalMediaManager.getSelectedMediaDevice()); MediaDevice selectedInputDevice = mInputRouteManager.getSelectedInputDevice(); if (selectedInputDevice != null) { selectedDevices.add(selectedInputDevice); } return selectedDevices; } List<MediaDevice> getDeselectableMediaDevice() { return mLocalMediaManager.getDeselectableMediaDevice(); } Loading packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java +32 −5 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ import com.android.media.flags.Flags; import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.media.InputMediaDevice; import com.android.settingslib.media.InputRouteManager; import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.MediaDevice; import com.android.systemui.SysuiTestCase; Loading Loading @@ -100,6 +101,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Collections; import java.util.List; @SmallTest Loading @@ -115,6 +117,10 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { private static final String TEST_SONG = "test_song"; private static final String TEST_SESSION_ID = "test_session_id"; private static final String TEST_SESSION_NAME = "test_session_name"; private static final int MAX_VOLUME = 1; private static final int CURRENT_VOLUME = 0; private static final boolean VOLUME_FIXED_TRUE = true; @Mock private DialogTransitionAnimator mDialogTransitionAnimator; @Mock Loading Loading @@ -181,6 +187,7 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { private String mPackageName = null; private MediaSwitchingController mMediaSwitchingController; private LocalMediaManager mLocalMediaManager; private InputRouteManager mInputRouteManager; private List<MediaController> mMediaControllers = new ArrayList<>(); private List<MediaDevice> mMediaDevices = new ArrayList<>(); private List<NearbyDevice> mNearbyDevices = new ArrayList<>(); Loading Loading @@ -228,6 +235,10 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { mLocalMediaManager = spy(mMediaSwitchingController.mLocalMediaManager); when(mLocalMediaManager.isPreferenceRouteListingExist()).thenReturn(false); mMediaSwitchingController.mLocalMediaManager = mLocalMediaManager; mMediaSwitchingController.mInputRouteManager = new InputRouteManager(mContext, mAudioManager); mInputRouteManager = spy(mMediaSwitchingController.mInputRouteManager); mMediaSwitchingController.mInputRouteManager = mInputRouteManager; MediaDescription.Builder builder = new MediaDescription.Builder(); builder.setTitle(TEST_SONG); builder.setSubtitle(TEST_ARTIST); Loading Loading @@ -545,9 +556,6 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { // Output devices have changed. mMediaSwitchingController.onDeviceListUpdate(mMediaDevices); final int MAX_VOLUME = 1; final int CURRENT_VOLUME = 0; final boolean IS_VOLUME_FIXED = true; final MediaDevice mediaDevice3 = InputMediaDevice.create( mContext, Loading @@ -555,7 +563,7 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { AudioDeviceInfo.TYPE_BUILTIN_MIC, MAX_VOLUME, CURRENT_VOLUME, IS_VOLUME_FIXED); VOLUME_FIXED_TRUE); final MediaDevice mediaDevice4 = InputMediaDevice.create( mContext, Loading @@ -563,7 +571,7 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { AudioDeviceInfo.TYPE_WIRED_HEADSET, MAX_VOLUME, CURRENT_VOLUME, IS_VOLUME_FIXED); VOLUME_FIXED_TRUE); final List<MediaDevice> inputDevices = new ArrayList<>(); inputDevices.add(mediaDevice3); inputDevices.add(mediaDevice4); Loading Loading @@ -1312,4 +1320,23 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { verify(mCallback).dismissDialog(); } @EnableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL) @Test public void getSelectedMediaDevice() { // Mock MediaDevice since none of the output media device constructor is publicly available // outside of SettingsLib package. final MediaDevice selectedOutputMediaDevice = mock(MediaDevice.class); doReturn(Collections.singletonList(selectedOutputMediaDevice)) .when(mLocalMediaManager) .getSelectedMediaDevice(); // Mock selected input media device. final MediaDevice selectedInputMediaDevice = mock(MediaDevice.class); doReturn(selectedInputMediaDevice).when(mInputRouteManager).getSelectedInputDevice(); List<MediaDevice> selectedMediaDevices = mMediaSwitchingController.getSelectedMediaDevice(); assertThat(selectedMediaDevices) .containsExactly(selectedOutputMediaDevice, selectedInputMediaDevice); } } Loading
packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java +4 −0 Original line number Diff line number Diff line Loading @@ -80,6 +80,10 @@ public class InputMediaDevice extends MediaDevice { context, id, audioDeviceInfoType, maxVolume, currentVolume, isVolumeFixed); } public @AudioDeviceType int getAudioDeviceInfoType() { return mAudioDeviceInfoType; } public static boolean isSupportedInputDevice(@AudioDeviceType int audioDeviceInfoType) { return switch (audioDeviceInfoType) { case TYPE_BUILTIN_MIC, Loading
packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java +37 −1 Original line number Diff line number Diff line Loading @@ -15,13 +15,20 @@ */ package com.android.settingslib.media; import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED; import android.content.Context; import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceCallback; import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.media.MediaRecorder; import android.os.Handler; import android.util.Slog; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; Loading @@ -35,12 +42,18 @@ public final class InputRouteManager { private static final String TAG = "InputRouteManager"; @VisibleForTesting static final AudioAttributes INPUT_ATTRIBUTES = new AudioAttributes.Builder().setCapturePreset(MediaRecorder.AudioSource.MIC).build(); private final Context mContext; private final AudioManager mAudioManager; @VisibleForTesting final List<MediaDevice> mInputMediaDevices = new CopyOnWriteArrayList<>(); private MediaDevice mSelectedInputDevice; private final Collection<InputDeviceCallback> mCallbacks = new CopyOnWriteArrayList<>(); @VisibleForTesting Loading Loading @@ -76,8 +89,27 @@ public final class InputRouteManager { mCallbacks.remove(callback); } public @Nullable MediaDevice getSelectedInputDevice() { return mSelectedInputDevice; } private void dispatchInputDeviceListUpdate() { // TODO (b/360175574): Get selected input device. // Get selected input device. List<AudioDeviceAttributes> attributesOfSelectedInputDevices = mAudioManager.getDevicesForAttributes(INPUT_ATTRIBUTES); int selectedInputDeviceAttributesType; if (attributesOfSelectedInputDevices.isEmpty()) { Slog.e(TAG, "Unexpected empty list of input devices. Using built-in mic."); selectedInputDeviceAttributesType = AudioDeviceInfo.TYPE_BUILTIN_MIC; } else { if (attributesOfSelectedInputDevices.size() > 1) { Slog.w( TAG, "AudioManager.getDevicesForAttributes returned more than one element." + " Using the first one."); } selectedInputDeviceAttributesType = attributesOfSelectedInputDevices.get(0).getType(); } // Get all input devices. AudioDeviceInfo[] audioDeviceInfos = Loading @@ -93,6 +125,10 @@ public final class InputRouteManager { getCurrentInputGain(), isInputGainFixed()); if (mediaDevice != null) { if (info.getType() == selectedInputDeviceAttributesType) { mediaDevice.setState(STATE_SELECTED); mSelectedInputDevice = mediaDevice; } mInputMediaDevices.add(mediaDevice); } } Loading
packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java +98 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.settingslib.media; import static com.android.settingslib.media.InputRouteManager.INPUT_ATTRIBUTES; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; Loading @@ -23,6 +25,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; import android.media.AudioManager; Loading @@ -36,6 +39,10 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.Collections; import java.util.List; @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowRouter2Manager.class}) public class InputRouteManagerTest { Loading Loading @@ -123,6 +130,97 @@ public class InputRouteManagerTest { assertThat(inputRouteManager.mInputMediaDevices).isEmpty(); } @Test public void getSelectedInputDevice_returnOneFromAudioManager() { final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class); when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET); when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID); final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class); when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC); when(info2.getId()).thenReturn(BUILTIN_MIC_ID); final AudioManager audioManager = mock(AudioManager.class); AudioDeviceInfo[] devices = {info1, info2}; when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices); // Mock audioManager.getDevicesForAttributes returns exactly one audioDeviceAttributes. AudioDeviceAttributes audioDeviceAttributes = new AudioDeviceAttributes(info1); when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES)) .thenReturn(Collections.singletonList(audioDeviceAttributes)); InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices); // The selected input device has the same type as the one returned from AudioManager. InputMediaDevice selectedInputDevice = (InputMediaDevice) inputRouteManager.getSelectedInputDevice(); assertThat(selectedInputDevice.getAudioDeviceInfoType()) .isEqualTo(AudioDeviceInfo.TYPE_WIRED_HEADSET); } @Test public void getSelectedInputDevice_returnMoreThanOneFromAudioManager() { final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class); when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET); when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID); final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class); when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC); when(info2.getId()).thenReturn(BUILTIN_MIC_ID); final AudioManager audioManager = mock(AudioManager.class); AudioDeviceInfo[] devices = {info1, info2}; when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices); // Mock audioManager.getDevicesForAttributes returns more than one audioDeviceAttributes. AudioDeviceAttributes audioDeviceAttributes1 = new AudioDeviceAttributes(info1); AudioDeviceAttributes audioDeviceAttributes2 = new AudioDeviceAttributes(info2); List<AudioDeviceAttributes> attributesOfSelectedInputDevices = new ArrayList<>(); attributesOfSelectedInputDevices.add(audioDeviceAttributes1); attributesOfSelectedInputDevices.add(audioDeviceAttributes2); when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES)) .thenReturn(attributesOfSelectedInputDevices); InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices); // The selected input device has the same type as the first one returned from AudioManager. InputMediaDevice selectedInputDevice = (InputMediaDevice) inputRouteManager.getSelectedInputDevice(); assertThat(selectedInputDevice.getAudioDeviceInfoType()) .isEqualTo(AudioDeviceInfo.TYPE_WIRED_HEADSET); } @Test public void getSelectedInputDevice_returnEmptyFromAudioManager() { final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class); when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET); when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID); final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class); when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC); when(info2.getId()).thenReturn(BUILTIN_MIC_ID); final AudioManager audioManager = mock(AudioManager.class); AudioDeviceInfo[] devices = {info1, info2}; when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices); // Mock audioManager.getDevicesForAttributes returns empty list of audioDeviceAttributes. List<AudioDeviceAttributes> attributesOfSelectedInputDevices = new ArrayList<>(); when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES)) .thenReturn(attributesOfSelectedInputDevices); InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices); // The selected input device has default type AudioDeviceInfo.TYPE_BUILTIN_MIC. InputMediaDevice selectedInputDevice = (InputMediaDevice) inputRouteManager.getSelectedInputDevice(); assertThat(selectedInputDevice.getAudioDeviceInfoType()) .isEqualTo(AudioDeviceInfo.TYPE_BUILTIN_MIC); } @Test public void getMaxInputGain_returnMaxInputGain() { assertThat(mInputRouteManager.getMaxInputGain()).isEqualTo(15); Loading
packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java +13 −2 Original line number Diff line number Diff line Loading @@ -157,7 +157,7 @@ public class MediaSwitchingController @VisibleForTesting boolean mNeedRefresh = false; private MediaController mMediaController; private InputRouteManager mInputRouteManager; @VisibleForTesting InputRouteManager mInputRouteManager; @VisibleForTesting Callback mCallback; @VisibleForTesting Loading Loading @@ -927,9 +927,20 @@ public class MediaSwitchingController } public List<MediaDevice> getSelectedMediaDevice() { if (!enableInputRouting()) { return mLocalMediaManager.getSelectedMediaDevice(); } // Add selected input device if input routing is supported. List<MediaDevice> selectedDevices = new ArrayList<>(mLocalMediaManager.getSelectedMediaDevice()); MediaDevice selectedInputDevice = mInputRouteManager.getSelectedInputDevice(); if (selectedInputDevice != null) { selectedDevices.add(selectedInputDevice); } return selectedDevices; } List<MediaDevice> getDeselectableMediaDevice() { return mLocalMediaManager.getDeselectableMediaDevice(); } Loading
packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java +32 −5 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ import com.android.media.flags.Flags; import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.media.InputMediaDevice; import com.android.settingslib.media.InputRouteManager; import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.MediaDevice; import com.android.systemui.SysuiTestCase; Loading Loading @@ -100,6 +101,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Collections; import java.util.List; @SmallTest Loading @@ -115,6 +117,10 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { private static final String TEST_SONG = "test_song"; private static final String TEST_SESSION_ID = "test_session_id"; private static final String TEST_SESSION_NAME = "test_session_name"; private static final int MAX_VOLUME = 1; private static final int CURRENT_VOLUME = 0; private static final boolean VOLUME_FIXED_TRUE = true; @Mock private DialogTransitionAnimator mDialogTransitionAnimator; @Mock Loading Loading @@ -181,6 +187,7 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { private String mPackageName = null; private MediaSwitchingController mMediaSwitchingController; private LocalMediaManager mLocalMediaManager; private InputRouteManager mInputRouteManager; private List<MediaController> mMediaControllers = new ArrayList<>(); private List<MediaDevice> mMediaDevices = new ArrayList<>(); private List<NearbyDevice> mNearbyDevices = new ArrayList<>(); Loading Loading @@ -228,6 +235,10 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { mLocalMediaManager = spy(mMediaSwitchingController.mLocalMediaManager); when(mLocalMediaManager.isPreferenceRouteListingExist()).thenReturn(false); mMediaSwitchingController.mLocalMediaManager = mLocalMediaManager; mMediaSwitchingController.mInputRouteManager = new InputRouteManager(mContext, mAudioManager); mInputRouteManager = spy(mMediaSwitchingController.mInputRouteManager); mMediaSwitchingController.mInputRouteManager = mInputRouteManager; MediaDescription.Builder builder = new MediaDescription.Builder(); builder.setTitle(TEST_SONG); builder.setSubtitle(TEST_ARTIST); Loading Loading @@ -545,9 +556,6 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { // Output devices have changed. mMediaSwitchingController.onDeviceListUpdate(mMediaDevices); final int MAX_VOLUME = 1; final int CURRENT_VOLUME = 0; final boolean IS_VOLUME_FIXED = true; final MediaDevice mediaDevice3 = InputMediaDevice.create( mContext, Loading @@ -555,7 +563,7 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { AudioDeviceInfo.TYPE_BUILTIN_MIC, MAX_VOLUME, CURRENT_VOLUME, IS_VOLUME_FIXED); VOLUME_FIXED_TRUE); final MediaDevice mediaDevice4 = InputMediaDevice.create( mContext, Loading @@ -563,7 +571,7 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { AudioDeviceInfo.TYPE_WIRED_HEADSET, MAX_VOLUME, CURRENT_VOLUME, IS_VOLUME_FIXED); VOLUME_FIXED_TRUE); final List<MediaDevice> inputDevices = new ArrayList<>(); inputDevices.add(mediaDevice3); inputDevices.add(mediaDevice4); Loading Loading @@ -1312,4 +1320,23 @@ public class MediaSwitchingControllerTest extends SysuiTestCase { verify(mCallback).dismissDialog(); } @EnableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL) @Test public void getSelectedMediaDevice() { // Mock MediaDevice since none of the output media device constructor is publicly available // outside of SettingsLib package. final MediaDevice selectedOutputMediaDevice = mock(MediaDevice.class); doReturn(Collections.singletonList(selectedOutputMediaDevice)) .when(mLocalMediaManager) .getSelectedMediaDevice(); // Mock selected input media device. final MediaDevice selectedInputMediaDevice = mock(MediaDevice.class); doReturn(selectedInputMediaDevice).when(mInputRouteManager).getSelectedInputDevice(); List<MediaDevice> selectedMediaDevices = mMediaSwitchingController.getSelectedMediaDevice(); assertThat(selectedMediaDevices) .containsExactly(selectedOutputMediaDevice, selectedInputMediaDevice); } }