Merge "Apply default selected device to all presets" into main
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());
     }
 }