Refactor generate car audio device info method

Moved the method to utility class so that the same logic can be used in
other files.

Bug: 359686069
Test: atest com.android.car.audio
Flag: android.car.feature.audio_control_hal_configuration
Change-Id: I9c85c5aad15043e5c36420536fbf051ec9e8ae59
diff --git a/service/src/com/android/car/audio/CarAudioService.java b/service/src/com/android/car/audio/CarAudioService.java
index 838d24f..48f9b9f 100644
--- a/service/src/com/android/car/audio/CarAudioService.java
+++ b/service/src/com/android/car/audio/CarAudioService.java
@@ -16,8 +16,8 @@
 package com.android.car.audio;
 
 import static android.car.builtin.media.AudioManagerHelper.UNDEFINED_STREAM_TYPE;
-import static android.car.feature.Flags.carAudioFadeManagerConfiguration;
 import static android.car.feature.Flags.asyncAudioServiceInit;
+import static android.car.feature.Flags.carAudioFadeManagerConfiguration;
 import static android.car.media.CarAudioManager.AUDIO_FEATURE_AUDIO_MIRRORING;
 import static android.car.media.CarAudioManager.AUDIO_FEATURE_DYNAMIC_ROUTING;
 import static android.car.media.CarAudioManager.AUDIO_FEATURE_MIN_MAX_ACTIVATION_VOLUME;
@@ -50,6 +50,7 @@
 import static com.android.car.audio.CarAudioUtils.convertVolumeChangeToEvent;
 import static com.android.car.audio.CarAudioUtils.convertVolumeChangesToEvents;
 import static com.android.car.audio.CarAudioUtils.excludesDynamicDevices;
+import static com.android.car.audio.CarAudioUtils.generateCarAudioDeviceInfos;
 import static com.android.car.audio.CarAudioUtils.getDynamicDevicesInConfig;
 import static com.android.car.audio.hal.AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_DUCKING;
 import static com.android.car.audio.hal.AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_FOCUS;
@@ -1942,29 +1943,6 @@
         AudioManagerHelper.registerVolumeAndMuteReceiver(mContext, mLegacyVolumeChangedHelper);
     }
 
-    private List<CarAudioDeviceInfo> generateCarAudioDeviceInfos() {
-        AudioDeviceInfo[] deviceInfos = mAudioManagerWrapper.getDevices(
-                AudioManager.GET_DEVICES_OUTPUTS);
-
-        List<CarAudioDeviceInfo> carInfos = new ArrayList<>();
-
-        for (int index = 0; index < deviceInfos.length; index++) {
-            if (!isValidDeviceType(deviceInfos[index].getType())) {
-                continue;
-            }
-
-            AudioDeviceInfo info = deviceInfos[index];
-            AudioDeviceAttributes attributes = new AudioDeviceAttributes(info);
-            CarAudioDeviceInfo carInfo = new CarAudioDeviceInfo(mAudioManagerWrapper, attributes);
-            // TODO(b/305301155): Move set audio device info closer to where it is used.
-            //  On dynamic configuration change for example
-            carInfo.setAudioDeviceInfo(info);
-
-            carInfos.add(carInfo);
-        }
-        return carInfos;
-    }
-
     private AudioDeviceInfo[] getAllInputDevices() {
         return mAudioManagerWrapper.getDevices(
                 AudioManager.GET_DEVICES_INPUTS);
@@ -2070,7 +2048,8 @@
             mCarAudioFadeConfigurationHelper = loadCarAudioFadeConfigurationLocked();
         }
 
-        List<CarAudioDeviceInfo> carAudioDeviceInfos = generateCarAudioDeviceInfos();
+        List<CarAudioDeviceInfo> carAudioDeviceInfos =
+                generateCarAudioDeviceInfos(mAudioManagerWrapper);
         AudioDeviceInfo[] inputDevices = getAllInputDevices();
 
         if (mCarAudioConfigurationPath != null) {
@@ -2429,13 +2408,6 @@
         mCarAudioModuleChangeMonitor = null;
     }
 
-    /*
-     * Currently only BUS and BUILT_SPEAKER devices are valid static devices.
-     */
-    private static boolean isValidDeviceType(int type) {
-        return type == AudioDeviceInfo.TYPE_BUS || type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
-    }
-
     /**
      * Read from {@link #AUDIO_CONFIGURATION_PATHS} respectively.
      * @return File path of the first hit in {@link #AUDIO_CONFIGURATION_PATHS}
diff --git a/service/src/com/android/car/audio/CarAudioUtils.java b/service/src/com/android/car/audio/CarAudioUtils.java
index a9eeaa6..45127cc 100644
--- a/service/src/com/android/car/audio/CarAudioUtils.java
+++ b/service/src/com/android/car/audio/CarAudioUtils.java
@@ -44,6 +44,7 @@
 import android.media.AudioAttributes;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 
@@ -202,6 +203,30 @@
         return addressToInputDevice;
     }
 
+    static List<CarAudioDeviceInfo> generateCarAudioDeviceInfos(AudioManagerWrapper audioManager) {
+        Objects.requireNonNull(audioManager, "Audio manager can not be null");
+        AudioDeviceInfo[] deviceInfos = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+        List<CarAudioDeviceInfo> carInfos = new ArrayList<>();
+        for (int index = 0; index < deviceInfos.length; index++) {
+            if (!isValidDeviceType(deviceInfos[index].getType())) {
+                continue;
+            }
+            AudioDeviceInfo info = deviceInfos[index];
+            AudioDeviceAttributes attributes = new AudioDeviceAttributes(info);
+            CarAudioDeviceInfo carInfo = new CarAudioDeviceInfo(audioManager, attributes);
+            carInfo.setAudioDeviceInfo(info);
+            carInfos.add(carInfo);
+        }
+        return carInfos;
+    }
+
+    /*
+     * Currently only BUS and BUILT_SPEAKER devices are valid static devices.
+     */
+    private static boolean isValidDeviceType(int type) {
+        return type == AudioDeviceInfo.TYPE_BUS || type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
+    }
+
     private static List<AudioDeviceInfo> getDynamicAudioDevices(
             List<CarVolumeGroupInfo> volumeGroups, AudioManagerWrapper manager) {
         List<AudioDeviceInfo> dynamicDevices = new ArrayList<>();
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioDeviceInfoTestUtils.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioDeviceInfoTestUtils.java
index 575ee0f..4fb33a6 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioDeviceInfoTestUtils.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioDeviceInfoTestUtils.java
@@ -50,6 +50,7 @@
     static final String TERTIARY_TEST_DEVICE_2 = "tertiary_zone_bus_200";
     static final String QUATERNARY_TEST_DEVICE_1 = "quaternary_zone_bus_1";
     static final String TEST_REAR_ROW_3_DEVICE = "rear_row_three_zone_bus_1";
+    static final String TEST_SPEAKER_DEVICE = "speaker";
 
     static final String ADDRESS_DOES_NOT_EXIST_DEVICE = "bus1000_does_not_exist";
 
@@ -70,6 +71,7 @@
     AudioDeviceInfo mRingOutputDevice;
     AudioDeviceInfo mAlarmOutputDevice;
     AudioDeviceInfo mSecondaryConfigOutputDevice;
+    AudioDeviceInfo mSpeakerDevice;
 
     private final List<AudioDeviceInfo> mAudioDeviceInfos;
 
@@ -123,6 +125,9 @@
                 .setAudioGains(new GainBuilder().build())
                 .setAddressName(SECONDARY_TEST_DEVICE_CONFIG_1_1)
                 .build();
+        mSpeakerDevice = new AudioDeviceInfoBuilder()
+                .setAudioGains(new GainBuilder().build())
+                .setAddressName(TEST_SPEAKER_DEVICE).build();
 
         mAudioDeviceInfos = List.of(
                 mBTAudioDeviceInfo,
@@ -137,6 +142,7 @@
                 mSecondaryConfig1Group0Device,
                 mSecondaryConfig1Group1Device,
                 mSecondaryConfigOutputDevice,
+                mSpeakerDevice,
                 new AudioDeviceInfoBuilder()
                         .setAudioGains(new GainBuilder().build())
                         .setAddressName(TERTIARY_TEST_DEVICE_1)
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioUtilsTest.java
index 837e906..c94e84d 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioUtilsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioUtilsTest.java
@@ -34,17 +34,28 @@
 import static android.media.AudioDeviceInfo.TYPE_USB_HEADSET;
 import static android.media.AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
 import static android.media.AudioDeviceInfo.TYPE_WIRED_HEADSET;
+import static android.media.AudioManager.GET_DEVICES_OUTPUTS;
 
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.ALARM_TEST_DEVICE;
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.CALL_TEST_DEVICE;
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.MEDIA_TEST_DEVICE;
+import static com.android.car.audio.CarAudioDeviceInfoTestUtils.MIRROR_TEST_DEVICE;
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.NAVIGATION_TEST_DEVICE;
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.NOTIFICATION_TEST_DEVICE;
+import static com.android.car.audio.CarAudioDeviceInfoTestUtils.OEM_TEST_DEVICE;
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.PRIMARY_ZONE_FM_TUNER_DEVICE;
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.PRIMARY_ZONE_MICROPHONE_DEVICE;
+import static com.android.car.audio.CarAudioDeviceInfoTestUtils.QUATERNARY_TEST_DEVICE_1;
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.RING_TEST_DEVICE;
+import static com.android.car.audio.CarAudioDeviceInfoTestUtils.SECONDARY_TEST_DEVICE_CONFIG_0;
+import static com.android.car.audio.CarAudioDeviceInfoTestUtils.SECONDARY_TEST_DEVICE_CONFIG_1_0;
+import static com.android.car.audio.CarAudioDeviceInfoTestUtils.SECONDARY_TEST_DEVICE_CONFIG_1_1;
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.SECONDARY_ZONE_BACK_MICROPHONE_DEVICE;
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.SYSTEM_BUS_DEVICE;
+import static com.android.car.audio.CarAudioDeviceInfoTestUtils.TERTIARY_TEST_DEVICE_1;
+import static com.android.car.audio.CarAudioDeviceInfoTestUtils.TERTIARY_TEST_DEVICE_2;
+import static com.android.car.audio.CarAudioDeviceInfoTestUtils.TEST_REAR_ROW_3_DEVICE;
+import static com.android.car.audio.CarAudioDeviceInfoTestUtils.TEST_SPEAKER_DEVICE;
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.VOICE_TEST_DEVICE;
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.generateCarAudioDeviceInfo;
 import static com.android.car.audio.CarAudioDeviceInfoTestUtils.generateInputAudioDeviceInfo;
@@ -53,6 +64,7 @@
 import static com.android.car.audio.CarAudioUtils.excludesDynamicDevices;
 import static com.android.car.audio.CarAudioUtils.generateAddressToCarAudioDeviceInfoMap;
 import static com.android.car.audio.CarAudioUtils.generateAddressToInputAudioDeviceInfoMap;
+import static com.android.car.audio.CarAudioUtils.generateCarAudioDeviceInfos;
 import static com.android.car.audio.CarAudioUtils.getAudioAttributesForDynamicDevices;
 import static com.android.car.audio.CarAudioUtils.getDynamicDevicesInConfig;
 import static com.android.car.audio.CarAudioUtils.hasExpired;
@@ -70,7 +82,6 @@
 import android.media.AudioAttributes;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
-import android.media.AudioManager;
 import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.annotation.NonNull;
@@ -417,6 +428,35 @@
                         SECONDARY_ZONE_BACK_MICROPHONE_DEVICE);
     }
 
+    @Test
+    public void generateCarAudioDeviceInfos_withNullManager() {
+        var thrown = assertThrows(NullPointerException.class,
+                () -> generateCarAudioDeviceInfos(/* audioManager = */ null));
+
+        expectWithMessage("Exception for generating car audio devices")
+                .that(thrown).hasMessageThat().contains("Audio manager");
+    }
+
+    @Test
+    public void generateCarAudioDeviceInfos_withValidDevicesInManager() {
+        var carAudioDeviceInfoTestUtils = new CarAudioDeviceInfoTestUtils();
+        var audioManager = Mockito.mock(AudioManagerWrapper.class);
+        var outputDevices = carAudioDeviceInfoTestUtils.generateOutputDeviceInfos();
+        when(audioManager.getDevices(GET_DEVICES_OUTPUTS)).thenReturn(outputDevices);
+
+        var carAudioDevices = generateCarAudioDeviceInfos(audioManager);
+
+        var addresses = carAudioDevices.stream().map(CarAudioDeviceInfo::getAddress).toList();
+        expectWithMessage("Generated car audio devices").that(addresses)
+                .containsExactly(MEDIA_TEST_DEVICE, OEM_TEST_DEVICE, MIRROR_TEST_DEVICE,
+                        NAVIGATION_TEST_DEVICE, CALL_TEST_DEVICE, NOTIFICATION_TEST_DEVICE,
+                        VOICE_TEST_DEVICE, RING_TEST_DEVICE, ALARM_TEST_DEVICE, SYSTEM_BUS_DEVICE,
+                        SECONDARY_TEST_DEVICE_CONFIG_0, SECONDARY_TEST_DEVICE_CONFIG_1_0,
+                        SECONDARY_TEST_DEVICE_CONFIG_1_1, TERTIARY_TEST_DEVICE_1,
+                        TERTIARY_TEST_DEVICE_2, QUATERNARY_TEST_DEVICE_1, TEST_REAR_ROW_3_DEVICE,
+                        TEST_SPEAKER_DEVICE);
+    }
+
     private List<CarAudioDeviceInfo> generateCarDeviceInfos() {
         return ImmutableList.of(
                 generateCarAudioDeviceInfo(MEDIA_TEST_DEVICE),
@@ -458,7 +498,7 @@
 
     private AudioManagerWrapper setUpMockAudioManager() {
         AudioManagerWrapper manager = Mockito.mock(AudioManagerWrapper.class);
-        when(manager.getDevices(AudioManager.GET_DEVICES_OUTPUTS))
+        when(manager.getDevices(GET_DEVICES_OUTPUTS))
                 .thenReturn(getMockOutputDevices());
         return manager;
     }