Updated VolumeSettingsRingtoneManager to read from configuration file to
determine mapping of audio attribute usage to ringtone.

Bug: 143985070
Test: Robolectric
Change-Id: Icef1e68e4706ff78c1ec1974dd2e44bc2b6ed4c8
Merged-In: Icef1e68e4706ff78c1ec1974dd2e44bc2b6ed4c8
diff --git a/res/values/config.xml b/res/values/config.xml
index 67c2f3d..a00ed09 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -45,6 +45,43 @@
         major class for PHONE.
     -->
     <integer-array name="config_unbonded_device_filter_whitelist"/>
+    <!--
+        Array of keys that should be used for determining how audio attribute
+        usage should be mapped to ringtone uris.
+
+        The values of the keys can be found in android.media.AudioAttributes.
+        The number of items in this array must equal the number of items in
+        config_ringtone_uri_map_value, and the usages are mapped to the ringtone
+        uri based on positions in the array. The lowest rank usage (based on the
+        order in car_volume_items.xml) in each audio group (in Car service's
+        car_volume_groups.xml) will be used to sound for a given volume group's
+        slider.
+
+        If empty, all ringtones will default to the default ringtone uri.
+
+        TODO(b/144382611): Instead of mapping by usage, we should map by audio
+        group so as to make it clearer to define the sound to be played with a
+        given slider.
+    -->
+    <integer-array name="config_ringtone_audio_attribute_usages_map_key">
+        <item>5</item>
+        <item>4</item>
+    </integer-array>
+    <!--
+        Array of values that should be used to determine how audio attribute
+        usage should be mapped to ringtone uris.
+
+        The values should be uri strings that can be parsed into Uri. The number
+        of items in this array must equal the number of items in
+        config_ringtone_audio_attributes_map_key, and the ringtone uris are
+        mapped to the audio attributes based on positions in the array.
+
+        If empty, all ringtones will default to the default ringtone uri.
+    -->
+    <string-array name="config_ringtone_uri_map_value">
+        <item>content://settings/system/notification_sound</item>
+        <item>content://settings/system/alarm_alert</item>
+    </string-array>
     <!-- Whether all preferences should always ignore UX Restrictions -->
     <bool name="config_always_ignore_ux_restrictions">false</bool>
     <!-- Array of Preference Keys that ignore UX Restrictions -->
diff --git a/src/com/android/car/settings/sound/VolumeSettingsRingtoneManager.java b/src/com/android/car/settings/sound/VolumeSettingsRingtoneManager.java
index 51f8bd8..a6c406b 100644
--- a/src/com/android/car/settings/sound/VolumeSettingsRingtoneManager.java
+++ b/src/com/android/car/settings/sound/VolumeSettingsRingtoneManager.java
@@ -26,6 +26,10 @@
 import android.provider.Settings;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.car.settings.R;
+import com.android.car.settings.common.Logger;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -33,11 +37,14 @@
 /** Manges the audio played by the {@link VolumeSettingsPreferenceController}. */
 public class VolumeSettingsRingtoneManager {
 
+    private static final Logger LOG = new Logger(VolumeSettingsRingtoneManager.class);
+
     private static final int AUDIO_FEEDBACK_DURATION_MS = 1000;
 
     private final Context mContext;
     private final Handler mUiHandler;
     private final Map<Integer, Ringtone> mGroupToRingtoneMap = new HashMap<>();
+    private final Map<Integer, Uri> mAttributeUsageToRingtoneUriMap = new HashMap<>();
 
     @Nullable
     private Ringtone mCurrentRingtone;
@@ -45,6 +52,32 @@
     public VolumeSettingsRingtoneManager(Context context) {
         mContext = context;
         mUiHandler = new Handler(Looper.getMainLooper());
+        populateAttributeUsageToRingtoneUriMap();
+    }
+
+    private void populateAttributeUsageToRingtoneUriMap() {
+        int[] audioAttributeUsages = mContext
+            .getResources()
+            .getIntArray(R.array.config_ringtone_audio_attribute_usages_map_key);
+        String[] ringtoneStrings = mContext
+            .getResources()
+            .getStringArray(R.array.config_ringtone_uri_map_value);
+        if (audioAttributeUsages.length != ringtoneStrings.length) {
+            throw new IllegalArgumentException(
+                "config_ringtone_audio_attribute_usages_map_key and config_ringtone_uri_map_value "
+                + "must have the same number of items");
+        }
+
+        for (int i = 0; i < audioAttributeUsages.length; i++) {
+            @AudioAttributes.AttributeUsage int usage = audioAttributeUsages[i];
+            if (AudioAttributes.usageToString(usage).contains("unknown usage")) {
+                throw new IllegalArgumentException(
+                    "Invalid usage in config_ringtone_audio_attribute_usages_map_key");
+            }
+            Uri ringtoneUri = Uri.parse(ringtoneStrings[i]);
+            LOG.d("Usage " + usage + " mapped to ringtone " + ringtoneUri);
+            mAttributeUsageToRingtoneUriMap.put(usage, ringtoneUri);
+        }
     }
 
     /**
@@ -87,14 +120,9 @@
     }
 
     // TODO: bundle car-specific audio sample assets in res/raw by usage
-    private Uri getRingtoneUri(@AudioAttributes.AttributeUsage int usage) {
-        switch (usage) {
-            case AudioAttributes.USAGE_NOTIFICATION:
-                return Settings.System.DEFAULT_NOTIFICATION_URI;
-            case AudioAttributes.USAGE_ALARM:
-                return Settings.System.DEFAULT_ALARM_ALERT_URI;
-            default:
-                return Settings.System.DEFAULT_RINGTONE_URI;
-        }
+    @VisibleForTesting
+    Uri getRingtoneUri(@AudioAttributes.AttributeUsage int usage) {
+        return mAttributeUsageToRingtoneUriMap.getOrDefault(
+            usage, Settings.System.DEFAULT_RINGTONE_URI);
     }
 }
diff --git a/tests/robotests/src/com/android/car/settings/sound/VolumeSettingsRingtoneManagerTest.java b/tests/robotests/src/com/android/car/settings/sound/VolumeSettingsRingtoneManagerTest.java
index b6e3f85..9de35b6 100644
--- a/tests/robotests/src/com/android/car/settings/sound/VolumeSettingsRingtoneManagerTest.java
+++ b/tests/robotests/src/com/android/car/settings/sound/VolumeSettingsRingtoneManagerTest.java
@@ -16,14 +16,25 @@
 
 package com.android.car.settings.sound;
 
+import static android.media.AudioAttributes.USAGE_ALARM;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.media.AudioAttributes.AttributeUsage;
 import android.media.Ringtone;
+import android.net.Uri;
+import android.provider.Settings.System;
 
 import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.R;
 import com.android.car.settings.testutils.ShadowRingtoneManager;
 
 import org.junit.After;
@@ -52,7 +63,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         ShadowRingtoneManager.setRingtone(mRingtone);
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
         mRingtoneManager = new VolumeSettingsRingtoneManager(mContext);
     }
 
@@ -63,6 +74,40 @@
     }
 
     @Test
+    public void getRingtoneUri_defaultsToDefaultRingtoneUriIfConfigIsEmpty() {
+        setResources(new int[] {}, new String[] {});
+        mRingtoneManager = new VolumeSettingsRingtoneManager(mContext);
+        Uri ringtoneUri = mRingtoneManager.getRingtoneUri(USAGE_ALARM);
+
+        assertThat(ringtoneUri).isEqualTo(System.DEFAULT_RINGTONE_URI);
+    }
+
+    @Test
+    public void getRingtoneUri_defaultsToDefaultRingtoneUriIfUsageNotInConfig() {
+        setResources(
+                new int[] {USAGE_MEDIA},
+                new String[] {"content://settings/system/notification_sound"}
+        );
+        mRingtoneManager = new VolumeSettingsRingtoneManager(mContext);
+
+        Uri ringtoneUri = mRingtoneManager.getRingtoneUri(USAGE_ALARM);
+
+        assertThat(ringtoneUri).isEqualTo(System.DEFAULT_RINGTONE_URI);
+    }
+
+    @Test
+    public void getRingtoneUri_usesConfigValuesForUsageRingtoneMapping() {
+        @AttributeUsage int usage = USAGE_MEDIA;
+        String ringtoneValue = "content://settings/system/notification_sound";
+        setResources(new int[] {usage}, new String[] {ringtoneValue});
+        mRingtoneManager = new VolumeSettingsRingtoneManager(mContext);
+
+        Uri ringtoneUri = mRingtoneManager.getRingtoneUri(usage);
+
+        assertThat(ringtoneUri).isEqualTo(Uri.parse(ringtoneValue));
+    }
+
+    @Test
     public void testPlayAudioFeedback_play_playUntilTimeout() {
         mRingtoneManager.playAudioFeedback(TEST_GROUP_ID, TEST_USAGE_ID);
         verify(mRingtone).play();
@@ -92,4 +137,13 @@
         mRingtoneManager.stopCurrentRingtone();
         verify(mRingtone, never()).stop();
     }
+
+    private void setResources(int[] ringtoneAudioAttributeUsages, String[] ringtoneUris) {
+        Resources resources = spy(mContext.getResources());
+        when(mContext.getResources()).thenReturn(resources);
+        when(resources.getIntArray(R.array.config_ringtone_audio_attribute_usages_map_key))
+            .thenReturn(ringtoneAudioAttributeUsages);
+        when(resources.getStringArray(R.array.config_ringtone_uri_map_value))
+            .thenReturn(ringtoneUris);
+    }
 }