summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Wenyu Zhang <zhangwenyu@google.com> 2024-10-10 20:10:47 +0000
committer Wenyu Zhang <zhangwenyu@google.com> 2024-10-10 20:10:47 +0000
commit8f0f00551c7ed1de0c827b65cce6aaeb5a74a2ee (patch)
tree0adcd2e0fe2d9022b12c68f35116eda446e77ca6
parent2f809c5059c88215b9d90ab1cddb19bf8f4a419c (diff)
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
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java55
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java280
2 files changed, 214 insertions, 121 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
index 727662b80d98..4f315a2a2486 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.AudioAttributes;
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 @@ public final class InputRouteManager {
@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 @@ public final class InputRouteManager {
new AudioDeviceCallback() {
@Override
public void onAudioDevicesAdded(@NonNull AudioDeviceInfo[] addedDevices) {
- dispatchInputDeviceListUpdate();
+ applyDefaultSelectedTypeToAllPresets();
}
@Override
public void onAudioDevicesRemoved(@NonNull AudioDeviceInfo[] removedDevices) {
- dispatchInputDeviceListUpdate();
+ applyDefaultSelectedTypeToAllPresets();
}
};
@@ -92,9 +93,12 @@ public final class InputRouteManager {
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 @@ public final class InputRouteManager {
}
}
+ // 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 @@ public final class InputRouteManager {
}
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 @@ public final class InputRouteManager {
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 final class InputRouteManager {
}
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 @@ public final class InputRouteManager {
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 f63bfc70140d..782cee23fb42 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.android.settingslib.media.InputRouteManager.PRESETS;
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 @@ public class InputRouteManagerTest {
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 @@ public class InputRouteManagerTest {
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 @@ public class InputRouteManagerTest {
@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 @@ public class InputRouteManagerTest {
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 @@ public class InputRouteManagerTest {
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 @@ public class InputRouteManagerTest {
@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 @@ public class InputRouteManagerTest {
@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 class InputRouteManagerTest {
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 @@ public class InputRouteManagerTest {
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 @@ public class InputRouteManagerTest {
@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 @@ public class InputRouteManagerTest {
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());
}
}