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()))