Apply default selected device to all presets
When system is initialized, or when audio device is
connected/disconnected, the default active input device returned back
from AudioPolicyManager does not apply to all all capture presets.
This leads to an issue that the selected device shown in UI does not
match the real device used in some presets (e.g. recording), which
makes users confused. This CL fixes this problem by applying the
default selected device to all presets.
Change-Id: I80efab3db6afa41c67c671e3b6bb73666c151086
Bug: b/355684672, b/357123258
Test: InputRouteManagerTest
Flag: com.android.media.flags.enable_audio_input_device_routing_and_volume_control
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
index 727662b..4f315a2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
@@ -22,6 +22,7 @@
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceCallback;
import android.media.AudioDeviceInfo;
+import android.media.AudioDeviceInfo.AudioDeviceType;
import android.media.AudioManager;
import android.media.MediaRecorder;
import android.os.Handler;
@@ -63,7 +64,7 @@
@VisibleForTesting final List<MediaDevice> mInputMediaDevices = new CopyOnWriteArrayList<>();
- private MediaDevice mSelectedInputDevice;
+ private @AudioDeviceType int mSelectedInputDeviceType;
private final Collection<InputDeviceCallback> mCallbacks = new CopyOnWriteArrayList<>();
private final Object mCallbackLock = new Object();
@@ -73,12 +74,12 @@
new AudioDeviceCallback() {
@Override
public void onAudioDevicesAdded(@NonNull AudioDeviceInfo[] addedDevices) {
- dispatchInputDeviceListUpdate();
+ applyDefaultSelectedTypeToAllPresets();
}
@Override
public void onAudioDevicesRemoved(@NonNull AudioDeviceInfo[] removedDevices) {
- dispatchInputDeviceListUpdate();
+ applyDefaultSelectedTypeToAllPresets();
}
};
@@ -92,9 +93,12 @@
mAudioManager.addOnPreferredDevicesForCapturePresetChangedListener(
new HandlerExecutor(handler),
this::onPreferredDevicesForCapturePresetChangedListener);
+
+ applyDefaultSelectedTypeToAllPresets();
}
- private void onPreferredDevicesForCapturePresetChangedListener(
+ @VisibleForTesting
+ void onPreferredDevicesForCapturePresetChangedListener(
@MediaRecorder.SystemSource int capturePreset,
@NonNull List<AudioDeviceAttributes> devices) {
if (capturePreset == MediaRecorder.AudioSource.MIC) {
@@ -117,12 +121,30 @@
}
}
+ // TODO(b/355684672): handle edge case where there are two devices with the same type. Only
+ // using a single mSelectedInputDeviceType might not be enough to recognize the correct device.
public @Nullable MediaDevice getSelectedInputDevice() {
- return mSelectedInputDevice;
+ for (MediaDevice device : mInputMediaDevices) {
+ if (((InputMediaDevice) device).getAudioDeviceInfoType() == mSelectedInputDeviceType) {
+ return device;
+ }
+ }
+ return null;
}
- private void dispatchInputDeviceListUpdate() {
- // Get selected input device.
+ private void applyDefaultSelectedTypeToAllPresets() {
+ mSelectedInputDeviceType = retrieveDefaultSelectedDeviceType();
+ AudioDeviceAttributes deviceAttributes =
+ createInputDeviceAttributes(mSelectedInputDeviceType);
+ setPreferredDeviceForAllPresets(deviceAttributes);
+ }
+
+ private AudioDeviceAttributes createInputDeviceAttributes(@AudioDeviceType int type) {
+ // Address is not used.
+ return new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_INPUT, type, /* address= */ "");
+ }
+
+ private @AudioDeviceType int retrieveDefaultSelectedDeviceType() {
List<AudioDeviceAttributes> attributesOfSelectedInputDevices =
mAudioManager.getDevicesForAttributes(INPUT_ATTRIBUTES);
int selectedInputDeviceAttributesType;
@@ -138,7 +160,10 @@
}
selectedInputDeviceAttributesType = attributesOfSelectedInputDevices.get(0).getType();
}
+ return selectedInputDeviceAttributesType;
+ }
+ private void dispatchInputDeviceListUpdate() {
// Get all input devices.
AudioDeviceInfo[] audioDeviceInfos =
mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
@@ -154,9 +179,8 @@
isInputGainFixed(),
getProductNameFromAudioDeviceInfo(info));
if (mediaDevice != null) {
- if (info.getType() == selectedInputDeviceAttributesType) {
+ if (info.getType() == mSelectedInputDeviceType) {
mediaDevice.setState(STATE_SELECTED);
- mSelectedInputDevice = mediaDevice;
}
mInputMediaDevices.add(mediaDevice);
}
@@ -190,12 +214,12 @@
}
public void selectDevice(@NonNull MediaDevice device) {
- if (!(device instanceof InputMediaDevice)) {
+ if (!(device instanceof InputMediaDevice inputMediaDevice)) {
Slog.w(TAG, "This device is not an InputMediaDevice: " + device.getName());
return;
}
- if (device.equals(mSelectedInputDevice)) {
+ if (inputMediaDevice.getAudioDeviceInfoType() == mSelectedInputDeviceType) {
Slog.w(TAG, "This device is already selected: " + device.getName());
return;
}
@@ -206,12 +230,11 @@
return;
}
- // TODO(b/355684672): apply address for BT devices.
+ // Update mSelectedInputDeviceType directly based on user action.
+ mSelectedInputDeviceType = inputMediaDevice.getAudioDeviceInfoType();
+
AudioDeviceAttributes deviceAttributes =
- new AudioDeviceAttributes(
- AudioDeviceAttributes.ROLE_INPUT,
- ((InputMediaDevice) device).getAudioDeviceInfoType(),
- /* address= */ "");
+ createInputDeviceAttributes(inputMediaDevice.getAudioDeviceInfoType());
try {
setPreferredDeviceForAllPresets(deviceAttributes);
} catch (IllegalArgumentException e) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
index f63bfc7..782cee2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
@@ -21,6 +21,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -55,6 +56,7 @@
private static final int INPUT_USB_DEVICE_ID = 3;
private static final int INPUT_USB_HEADSET_ID = 4;
private static final int INPUT_USB_ACCESSORY_ID = 5;
+ private static final int HDMI_ID = 6;
private static final int MAX_VOLUME = 1;
private static final int CURRENT_VOLUME = 0;
private static final boolean VOLUME_FIXED_TRUE = true;
@@ -63,10 +65,86 @@
private static final String PRODUCT_NAME_USB_HEADSET = "My USB Headset";
private static final String PRODUCT_NAME_USB_DEVICE = "My USB Device";
private static final String PRODUCT_NAME_USB_ACCESSORY = "My USB Accessory";
+ private static final String PRODUCT_NAME_HDMI_DEVICE = "HDMI device";
private final Context mContext = spy(RuntimeEnvironment.application);
private InputRouteManager mInputRouteManager;
+ private AudioDeviceInfo mockBuiltinMicInfo() {
+ final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+ when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
+ when(info.getId()).thenReturn(BUILTIN_MIC_ID);
+ when(info.getAddress()).thenReturn("");
+ when(info.getProductName()).thenReturn(PRODUCT_NAME_BUILTIN_MIC);
+ return info;
+ }
+
+ private AudioDeviceInfo mockWiredHeadsetInfo() {
+ final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+ when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
+ when(info.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
+ when(info.getAddress()).thenReturn("");
+ when(info.getProductName()).thenReturn(PRODUCT_NAME_WIRED_HEADSET);
+ return info;
+ }
+
+ private AudioDeviceInfo mockUsbDeviceInfo() {
+ final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+ when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_DEVICE);
+ when(info.getId()).thenReturn(INPUT_USB_DEVICE_ID);
+ when(info.getAddress()).thenReturn("");
+ when(info.getProductName()).thenReturn(PRODUCT_NAME_USB_DEVICE);
+ return info;
+ }
+
+ private AudioDeviceInfo mockUsbHeadsetInfo() {
+ final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+ when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_HEADSET);
+ when(info.getId()).thenReturn(INPUT_USB_HEADSET_ID);
+ when(info.getAddress()).thenReturn("");
+ when(info.getProductName()).thenReturn(PRODUCT_NAME_USB_HEADSET);
+ return info;
+ }
+
+ private AudioDeviceInfo mockUsbAccessoryInfo() {
+ final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+ when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_ACCESSORY);
+ when(info.getId()).thenReturn(INPUT_USB_ACCESSORY_ID);
+ when(info.getAddress()).thenReturn("");
+ when(info.getProductName()).thenReturn(PRODUCT_NAME_USB_ACCESSORY);
+ return info;
+ }
+
+ private AudioDeviceInfo mockHdmiInfo() {
+ final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+ when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_HDMI);
+ when(info.getId()).thenReturn(HDMI_ID);
+ when(info.getAddress()).thenReturn("");
+ when(info.getProductName()).thenReturn(PRODUCT_NAME_HDMI_DEVICE);
+ return info;
+ }
+
+ private AudioDeviceAttributes getBuiltinMicDeviceAttributes() {
+ return new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_INPUT,
+ AudioDeviceInfo.TYPE_BUILTIN_MIC,
+ /* address= */ "");
+ }
+
+ private AudioDeviceAttributes getWiredHeadsetDeviceAttributes() {
+ return new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_INPUT,
+ AudioDeviceInfo.TYPE_WIRED_HEADSET,
+ /* address= */ "");
+ }
+
+ private void onPreferredDevicesForCapturePresetChanged(InputRouteManager inputRouteManager) {
+ final List<AudioDeviceAttributes> audioDeviceAttributesList =
+ new ArrayList<AudioDeviceAttributes>();
+ inputRouteManager.onPreferredDevicesForCapturePresetChangedListener(
+ MediaRecorder.AudioSource.MIC, audioDeviceAttributesList);
+ }
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -77,37 +155,15 @@
@Test
public void onAudioDevicesAdded_shouldUpdateInputMediaDevice() {
- final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class);
- when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
- when(info1.getId()).thenReturn(BUILTIN_MIC_ID);
- when(info1.getProductName()).thenReturn(PRODUCT_NAME_BUILTIN_MIC);
-
- final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
- when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
- when(info2.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
- when(info2.getProductName()).thenReturn(PRODUCT_NAME_WIRED_HEADSET);
-
- final AudioDeviceInfo info3 = mock(AudioDeviceInfo.class);
- when(info3.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_DEVICE);
- when(info3.getId()).thenReturn(INPUT_USB_DEVICE_ID);
- when(info3.getProductName()).thenReturn(PRODUCT_NAME_USB_DEVICE);
-
- final AudioDeviceInfo info4 = mock(AudioDeviceInfo.class);
- when(info4.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_HEADSET);
- when(info4.getId()).thenReturn(INPUT_USB_HEADSET_ID);
- when(info4.getProductName()).thenReturn(PRODUCT_NAME_USB_HEADSET);
-
- final AudioDeviceInfo info5 = mock(AudioDeviceInfo.class);
- when(info5.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_ACCESSORY);
- when(info5.getId()).thenReturn(INPUT_USB_ACCESSORY_ID);
- when(info5.getProductName()).thenReturn(PRODUCT_NAME_USB_ACCESSORY);
-
- final AudioDeviceInfo unsupportedInfo = mock(AudioDeviceInfo.class);
- when(unsupportedInfo.getType()).thenReturn(AudioDeviceInfo.TYPE_HDMI);
- when(unsupportedInfo.getProductName()).thenReturn("HDMI device");
-
final AudioManager audioManager = mock(AudioManager.class);
- AudioDeviceInfo[] devices = {info1, info2, info3, info4, info5, unsupportedInfo};
+ AudioDeviceInfo[] devices = {
+ mockBuiltinMicInfo(),
+ mockWiredHeadsetInfo(),
+ mockUsbDeviceInfo(),
+ mockUsbHeadsetInfo(),
+ mockUsbAccessoryInfo(),
+ mockHdmiInfo()
+ };
when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices);
InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
@@ -115,8 +171,9 @@
assertThat(inputRouteManager.mInputMediaDevices).isEmpty();
inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+ onPreferredDevicesForCapturePresetChanged(inputRouteManager);
- // The unsupported info should be filtered out.
+ // The unsupported (hdmi) info should be filtered out.
assertThat(inputRouteManager.mInputMediaDevices).hasSize(devices.length - 1);
assertThat(inputRouteManager.mInputMediaDevices.get(0).getId())
.isEqualTo(String.valueOf(BUILTIN_MIC_ID));
@@ -141,36 +198,25 @@
final MediaDevice device = mock(MediaDevice.class);
inputRouteManager.mInputMediaDevices.add(device);
- final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
- when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
- inputRouteManager.mAudioDeviceCallback.onAudioDevicesRemoved(new AudioDeviceInfo[] {info});
+ inputRouteManager.mAudioDeviceCallback.onAudioDevicesRemoved(
+ new AudioDeviceInfo[] {mockWiredHeadsetInfo()});
+ onPreferredDevicesForCapturePresetChanged(inputRouteManager);
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);
- when(info1.getProductName()).thenReturn(PRODUCT_NAME_WIRED_HEADSET);
-
- final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
- when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
- when(info2.getId()).thenReturn(BUILTIN_MIC_ID);
- when(info2.getProductName()).thenReturn(PRODUCT_NAME_BUILTIN_MIC);
-
final AudioManager audioManager = mock(AudioManager.class);
- AudioDeviceInfo[] devices = {info1, info2};
+ AudioDeviceInfo[] devices = {mockWiredHeadsetInfo(), mockBuiltinMicInfo()};
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));
+ .thenReturn(Collections.singletonList(getWiredHeadsetDeviceAttributes()));
InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
- inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+ onPreferredDevicesForCapturePresetChanged(inputRouteManager);
// The selected input device has the same type as the one returned from AudioManager.
InputMediaDevice selectedInputDevice =
@@ -181,31 +227,19 @@
@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);
- when(info1.getProductName()).thenReturn(PRODUCT_NAME_WIRED_HEADSET);
-
- final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
- when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
- when(info2.getId()).thenReturn(BUILTIN_MIC_ID);
- when(info2.getProductName()).thenReturn(PRODUCT_NAME_BUILTIN_MIC);
-
final AudioManager audioManager = mock(AudioManager.class);
- AudioDeviceInfo[] devices = {info1, info2};
+ AudioDeviceInfo[] devices = {mockWiredHeadsetInfo(), mockBuiltinMicInfo()};
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);
+ attributesOfSelectedInputDevices.add(getWiredHeadsetDeviceAttributes());
+ attributesOfSelectedInputDevices.add(getBuiltinMicDeviceAttributes());
when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES))
.thenReturn(attributesOfSelectedInputDevices);
InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
- inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+ onPreferredDevicesForCapturePresetChanged(inputRouteManager);
// The selected input device has the same type as the first one returned from AudioManager.
InputMediaDevice selectedInputDevice =
@@ -216,27 +250,17 @@
@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);
- when(info1.getProductName()).thenReturn(PRODUCT_NAME_WIRED_HEADSET);
-
- final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
- when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
- when(info2.getId()).thenReturn(BUILTIN_MIC_ID);
- when(info2.getProductName()).thenReturn(PRODUCT_NAME_BUILTIN_MIC);
-
final AudioManager audioManager = mock(AudioManager.class);
- AudioDeviceInfo[] devices = {info1, info2};
+ AudioDeviceInfo[] devices = {mockWiredHeadsetInfo(), mockBuiltinMicInfo()};
when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices);
// Mock audioManager.getDevicesForAttributes returns empty list of audioDeviceAttributes.
- List<AudioDeviceAttributes> attributesOfSelectedInputDevices = new ArrayList<>();
+ List<AudioDeviceAttributes> emptyAttributesOfSelectedInputDevices = new ArrayList<>();
when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES))
- .thenReturn(attributesOfSelectedInputDevices);
+ .thenReturn(emptyAttributesOfSelectedInputDevices);
InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
- inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+ onPreferredDevicesForCapturePresetChanged(inputRouteManager);
// The selected input device has default type AudioDeviceInfo.TYPE_BUILTIN_MIC.
InputMediaDevice selectedInputDevice =
@@ -249,7 +273,7 @@
public void selectDevice() {
final AudioManager audioManager = mock(AudioManager.class);
InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
- final MediaDevice inputMediaDevice =
+ final MediaDevice builtinMicDevice =
InputMediaDevice.create(
mContext,
String.valueOf(BUILTIN_MIC_ID),
@@ -258,16 +282,57 @@
CURRENT_VOLUME,
VOLUME_FIXED_TRUE,
PRODUCT_NAME_BUILTIN_MIC);
- inputRouteManager.selectDevice(inputMediaDevice);
+ inputRouteManager.selectDevice(builtinMicDevice);
- AudioDeviceAttributes deviceAttributes =
- new AudioDeviceAttributes(
- AudioDeviceAttributes.ROLE_INPUT,
- AudioDeviceInfo.TYPE_BUILTIN_MIC,
- /* address= */ "");
for (@MediaRecorder.Source int preset : PRESETS) {
verify(audioManager, atLeastOnce())
- .setPreferredDeviceForCapturePreset(preset, deviceAttributes);
+ .setPreferredDeviceForCapturePreset(preset, getBuiltinMicDeviceAttributes());
+ }
+ }
+
+ @Test
+ public void onInitiation_shouldApplyDefaultSelectedDeviceToAllPresets() {
+ final AudioManager audioManager = mock(AudioManager.class);
+ new InputRouteManager(mContext, audioManager);
+
+ verify(audioManager, atLeastOnce()).getDevicesForAttributes(INPUT_ATTRIBUTES);
+ for (@MediaRecorder.Source int preset : PRESETS) {
+ verify(audioManager, atLeastOnce())
+ .setPreferredDeviceForCapturePreset(preset, getBuiltinMicDeviceAttributes());
+ }
+ }
+
+ @Test
+ public void onAudioDevicesAdded_shouldApplyDefaultSelectedDeviceToAllPresets() {
+ final AudioManager audioManager = mock(AudioManager.class);
+ AudioDeviceAttributes wiredHeadsetDeviceAttributes = getWiredHeadsetDeviceAttributes();
+ when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES))
+ .thenReturn(Collections.singletonList(wiredHeadsetDeviceAttributes));
+
+ InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
+ AudioDeviceInfo[] devices = {mockWiredHeadsetInfo()};
+ inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+
+ // Called twice, one after initiation, the other after onAudioDevicesAdded call.
+ verify(audioManager, atLeast(2)).getDevicesForAttributes(INPUT_ATTRIBUTES);
+ for (@MediaRecorder.Source int preset : PRESETS) {
+ verify(audioManager, atLeast(2))
+ .setPreferredDeviceForCapturePreset(preset, wiredHeadsetDeviceAttributes);
+ }
+ }
+
+ @Test
+ public void onAudioDevicesRemoved_shouldApplyDefaultSelectedDeviceToAllPresets() {
+ final AudioManager audioManager = mock(AudioManager.class);
+ InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
+ AudioDeviceInfo[] devices = {mockWiredHeadsetInfo()};
+ inputRouteManager.mAudioDeviceCallback.onAudioDevicesRemoved(devices);
+
+ // Called twice, one after initiation, the other after onAudioDevicesRemoved call.
+ verify(audioManager, atLeast(2)).getDevicesForAttributes(INPUT_ATTRIBUTES);
+ for (@MediaRecorder.Source int preset : PRESETS) {
+ verify(audioManager, atLeast(2))
+ .setPreferredDeviceForCapturePreset(preset, getBuiltinMicDeviceAttributes());
}
}
@@ -288,27 +353,25 @@
@Test
public void onAudioDevicesAdded_shouldSetProductNameCorrectly() {
- final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class);
- when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
- when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
+ final AudioDeviceInfo info1 = mockWiredHeadsetInfo();
String firstProductName = "My first headset";
when(info1.getProductName()).thenReturn(firstProductName);
+ InputMediaDevice inputMediaDevice1 = createInputMediaDeviceFromDeviceInfo(info1);
- final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
- when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
- when(info2.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
+ final AudioDeviceInfo info2 = mockWiredHeadsetInfo();
String secondProductName = "My second headset";
when(info2.getProductName()).thenReturn(secondProductName);
+ InputMediaDevice inputMediaDevice2 = createInputMediaDeviceFromDeviceInfo(info2);
- final AudioDeviceInfo infoWithNullProductName = mock(AudioDeviceInfo.class);
- when(infoWithNullProductName.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
- when(infoWithNullProductName.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
+ final AudioDeviceInfo infoWithNullProductName = mockWiredHeadsetInfo();
when(infoWithNullProductName.getProductName()).thenReturn(null);
+ InputMediaDevice inputMediaDevice3 =
+ createInputMediaDeviceFromDeviceInfo(infoWithNullProductName);
- final AudioDeviceInfo infoWithBlankProductName = mock(AudioDeviceInfo.class);
- when(infoWithBlankProductName.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
- when(infoWithBlankProductName.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
+ final AudioDeviceInfo infoWithBlankProductName = mockWiredHeadsetInfo();
when(infoWithBlankProductName.getProductName()).thenReturn("");
+ InputMediaDevice inputMediaDevice4 =
+ createInputMediaDeviceFromDeviceInfo(infoWithBlankProductName);
final AudioManager audioManager = mock(AudioManager.class);
AudioDeviceInfo[] devices = {
@@ -321,15 +384,22 @@
assertThat(inputRouteManager.mInputMediaDevices).isEmpty();
inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+ onPreferredDevicesForCapturePresetChanged(inputRouteManager);
- assertThat(getProductNameAtIndex(inputRouteManager, 1)).isEqualTo(firstProductName);
- assertThat(getProductNameAtIndex(inputRouteManager, 2)).isEqualTo(secondProductName);
- assertThat(getProductNameAtIndex(inputRouteManager, 3)).isNull();
- assertThat(getProductNameAtIndex(inputRouteManager, 4)).isNull();
+ assertThat(inputRouteManager.mInputMediaDevices)
+ .containsExactly(
+ inputMediaDevice1, inputMediaDevice2, inputMediaDevice3, inputMediaDevice4)
+ .inOrder();
}
- private String getProductNameAtIndex(InputRouteManager inputRouteManager, int index) {
- return ((InputMediaDevice) inputRouteManager.mInputMediaDevices.get(index))
- .getProductName();
+ private InputMediaDevice createInputMediaDeviceFromDeviceInfo(AudioDeviceInfo info) {
+ return InputMediaDevice.create(
+ mContext,
+ String.valueOf(info.getId()),
+ info.getType(),
+ MAX_VOLUME,
+ CURRENT_VOLUME,
+ VOLUME_FIXED_TRUE,
+ info.getProductName() == null ? null : info.getProductName().toString());
}
}