Use AudioManager API instead of manually checking ringing volume.

This CL ensures that the Ringer class relies on the AudioManager#shouldNotificationSoundPlay API instead of manually checking ringing volume when determining if a ringtone should be played audibly for an MT call. This CL also adds the feature flag for all of the go/ring-my-car Telecom feature work.

Bug: 348707841
Flag: com.android.server.telecom.flags.ensure_in_car_ringing
Test: atest RingerTest

Change-Id: I7df60d54e4e6e8ede69e807a6091647104ea9863
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 90e4bd9..941bd5e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -45,6 +45,8 @@
     <!-- Required to determine source of ongoing audio recordings. -->
     <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING"/>
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
+    <!-- Required to query the audio framework to determine if a notification sound should play. -->
+    <uses-permission android:name="android.permission.QUERY_AUDIO_STATE"/>
     <uses-permission android:name="android.permission.READ_CALL_LOG"/>
     <!-- Required to check for direct to voicemail, to load custom ringtones for incoming calls
         which are specified on a per contact basis, and also to determine user preferred
diff --git a/flags/telecom_ringer_flag_declarations.aconfig b/flags/telecom_ringer_flag_declarations.aconfig
index f126bf3..6517e0f 100644
--- a/flags/telecom_ringer_flag_declarations.aconfig
+++ b/flags/telecom_ringer_flag_declarations.aconfig
@@ -7,4 +7,12 @@
   namespace: "telecom"
   description: "Gates whether to use a serialized, device-specific ring vibration."
   bug: "282113261"
+}
+
+# OWNER=grantmenke TARGET=24Q4
+flag {
+  name: "ensure_in_car_ringing"
+  namespace: "telecom"
+  description: "Gates whether to ensure that when a user is in their car, they are able to hear ringing for an incoming call."
+  bug: "348708398"
 }
\ No newline at end of file
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index e148ef5..3d08256 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -28,6 +28,7 @@
 import android.app.Person;
 import android.content.Context;
 import android.content.res.Resources;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.Ringtone;
 import android.media.VolumeShaper;
@@ -704,7 +705,16 @@
 
         LogUtils.EventTimer timer = new EventTimer();
 
-        boolean isVolumeOverZero = mAudioManager.getStreamVolume(AudioManager.STREAM_RING) > 0;
+        boolean isVolumeOverZero;
+
+        if (mFlags.ensureInCarRinging()) {
+            AudioAttributes aa = new AudioAttributes.Builder()
+                    .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).build();
+            isVolumeOverZero = mAudioManager.shouldNotificationSoundPlay(aa);
+        } else {
+            isVolumeOverZero = mAudioManager.getStreamVolume(AudioManager.STREAM_RING) > 0;
+        }
         timer.record("isVolumeOverZero");
         boolean shouldRingForContact = shouldRingForContact(call);
         timer.record("shouldRingForContact");
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 1c27b14..04dcef8 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -45,10 +45,13 @@
     <!-- Used to access PlatformCompat APIs -->
     <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
     <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
-    
+
     <!-- Used to register NotificationListenerService -->
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
 
+    <!-- Used to query the audio framework to determine if a notification sound should play. -->
+    <uses-permission android:name="android.permission.QUERY_AUDIO_STATE"/>
+
     <application android:label="@string/app_name"
                  android:debuggable="true">
         <uses-library android:name="android.test.runner" />
diff --git a/tests/src/com/android/server/telecom/tests/RingerTest.java b/tests/src/com/android/server/telecom/tests/RingerTest.java
index 1215fd3..f615f7e 100644
--- a/tests/src/com/android/server/telecom/tests/RingerTest.java
+++ b/tests/src/com/android/server/telecom/tests/RingerTest.java
@@ -136,6 +136,7 @@
         super.setUp();
         mContext = spy(mComponentContextFixture.getTestDouble().getApplicationContext());
         when(mFeatureFlags.telecomResolveHiddenDependencies()).thenReturn(true);
+        when(mFeatureFlags.ensureInCarRinging()).thenReturn(false);
         doReturn(URI_VIBRATION_EFFECT).when(spyVibrationEffectProxy).get(any(), any());
         when(mockPlayerFactory.createPlayer(any(Call.class), anyInt())).thenReturn(mockTonePlayer);
         mockAudioManager = mContext.getSystemService(AudioManager.class);
@@ -438,6 +439,66 @@
 
     @SmallTest
     @Test
+    public void testAudibleRingWhenNotificationSoundShouldPlay() throws Exception {
+        when(mFeatureFlags.ensureInCarRinging()).thenReturn(true);
+        Ringtone mockRingtone = ensureRingtoneMocked();
+
+        mRingerUnderTest.startCallWaiting(mockCall1);
+        AudioAttributes aa = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).build();
+        // Set AudioManager#shouldNotificationSoundPlay to true:
+        when(mockAudioManager.shouldNotificationSoundPlay(aa)).thenReturn(true);
+        enableVibrationWhenRinging();
+
+        // This will set AudioManager#getStreamVolume to 0. This test ensures that whether a
+        // ringtone is audible is controlled by AudioManager#shouldNotificationSoundPlay instead:
+        ensureRingerIsNotAudible();
+
+        // Ensure an audible ringtone is played:
+        assertTrue(startRingingAndWaitForAsync(mockCall2, false));
+        verify(mockTonePlayer).stopTone();
+        verify(mockRingtoneFactory, atLeastOnce()).getRingtone(any(Call.class),
+                nullable(VolumeShaper.Configuration.class), anyBoolean());
+        verifyNoMoreInteractions(mockRingtoneFactory);
+        verify(mockRingtone).play();
+
+        // Ensure a vibration plays:
+        verify(mockVibrator).vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
+    }
+
+    @SmallTest
+    @Test
+    public void testNoAudibleRingWhenNotificationSoundShouldNotPlay() throws Exception {
+        when(mFeatureFlags.ensureInCarRinging()).thenReturn(true);
+        Ringtone mockRingtone = ensureRingtoneMocked();
+
+        mRingerUnderTest.startCallWaiting(mockCall1);
+        AudioAttributes aa = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).build();
+        // Set AudioManager#shouldNotificationSoundPlay to false:
+        when(mockAudioManager.shouldNotificationSoundPlay(aa)).thenReturn(false);
+        enableVibrationWhenRinging();
+
+        // This will set AudioManager#getStreamVolume to 100. This test ensures that whether a
+        // ringtone is audible is controlled by AudioManager#shouldNotificationSoundPlay instead:
+        ensureRingerIsAudible();
+
+        // Ensure no audible ringtone is played:
+        assertFalse(startRingingAndWaitForAsync(mockCall2, false));
+        verify(mockTonePlayer).stopTone();
+        // Ensure a silent haptics only ringtone is played:
+        verify(mockRingtoneFactory, atLeastOnce()).getHapticOnlyRingtone();
+        verifyNoMoreInteractions(mockRingtoneFactory);
+        verify(mockRingtone).play();
+
+        // Ensure a vibration plays:
+        verify(mockVibrator).vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
+    }
+
+    @SmallTest
+    @Test
     public void testVibrateButNoRingForNullRingtone() throws Exception {
         when(mockRingtoneFactory.getRingtone(
                  any(Call.class), nullable(VolumeShaper.Configuration.class), anyBoolean()))