Loading src/com/android/server/telecom/Ringer.java +22 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.content.res.Resources; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.media.Utils; import android.media.VolumeShaper; import android.media.audio.Flags; Loading Loading @@ -431,6 +432,11 @@ public class Ringer { && isVibratorEnabled) { Log.i(this, "Muted haptic channels since audio coupled ramping ringer is disabled"); hapticChannelsMuted = true; if (useCustomVibration(foregroundCall)) { Log.i(this, "Not muted haptic channel for customization when apply ramping ringer"); hapticChannelsMuted = false; } } else if (hapticChannelsMuted) { Log.i(this, "Muted haptic channels isVibratorEnabled=%s, hapticPlaybackSupported=%s", Loading @@ -442,7 +448,7 @@ public class Ringer { if (!isHapticOnly) { ringtoneInfoSupplier = () -> mRingtoneFactory.getRingtone( foregroundCall, mVolumeShaperConfig, finalHapticChannelsMuted); } else if (Flags.enableRingtoneHapticsCustomization() && mRingtoneVibrationSupported) { } else if (useCustomVibration(foregroundCall)) { ringtoneInfoSupplier = () -> mRingtoneFactory.getRingtone( foregroundCall, null, false); } Loading Loading @@ -521,6 +527,21 @@ public class Ringer { } } private boolean useCustomVibration(@NonNull Call foregroundCall) { return Flags.enableRingtoneHapticsCustomization() && mRingtoneVibrationSupported && hasExplicitVibration(foregroundCall); } private boolean hasExplicitVibration(@NonNull Call foregroundCall) { final Uri ringtoneUri = foregroundCall.getRingtone(); if (ringtoneUri != null) { // TODO(b/399265235) : Avoid this hidden API access for mainline return Utils.hasVibration(ringtoneUri); } return Utils.hasVibration(RingtoneManager.getActualDefaultRingtoneUri( mContext, RingtoneManager.TYPE_RINGTONE)); } /** * Try to reserve the vibrator for this call, returning false if it's already committed. * The vibration will be started by AsyncRingtonePlayer to ensure timing is aligned with the Loading tests/src/com/android/server/telecom/tests/RingerTest.java +63 −15 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; Loading @@ -46,6 +47,7 @@ import android.content.Context; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.media.VolumeShaper; import android.media.audio.Flags; import android.net.Uri; Loading @@ -65,6 +67,7 @@ import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.util.Pair; import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; Loading @@ -85,6 +88,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Spy; Loading Loading @@ -846,8 +850,12 @@ public class RingerTest extends TelecomTestCase { @Test @EnableFlags(Flags.FLAG_ENABLE_RINGTONE_HAPTICS_CUSTOMIZATION) public void testNoVibrateForSilentRingtoneIfRingtoneHasVibration() throws Exception { final Context context = ApplicationProvider.getApplicationContext(); Uri defaultRingtoneUri = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE); assumeNotNull(defaultRingtoneUri); Uri FAKE_RINGTONE_VIBRATION_URI = FAKE_RINGTONE_URI.buildUpon().appendQueryParameter( defaultRingtoneUri.buildUpon().appendQueryParameter( VIBRATION_PARAM, FAKE_VIBRATION_URI.toString()).build(); Ringtone mockRingtone = mock(Ringtone.class); Pair<Uri, Ringtone> ringtoneInfo = new Pair(FAKE_RINGTONE_VIBRATION_URI, mockRingtone); Loading @@ -856,6 +864,9 @@ public class RingerTest extends TelecomTestCase { .thenReturn(ringtoneInfo); mComponentContextFixture.putBooleanResource( com.android.internal.R.bool.config_ringtoneVibrationSettingsSupported, true); try { RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, FAKE_RINGTONE_VIBRATION_URI); createRingerUnderTest(); // Needed after mock the config. mRingerUnderTest.startCallWaiting(mockCall1); Loading @@ -871,6 +882,43 @@ public class RingerTest extends TelecomTestCase { // Skip vibration play in Ringer if a vibration was specified to the ringtone verify(mockVibrator, never()).vibrate(any(VibrationEffect.class), any(VibrationAttributes.class)); } finally { // Restore the default ringtone Uri RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, defaultRingtoneUri); } } @SmallTest @Test @EnableFlags(Flags.FLAG_ENABLE_RINGTONE_HAPTICS_CUSTOMIZATION) public void testNotMuteHapticChannelWithRampingRinger() throws Exception { final Context context = ApplicationProvider.getApplicationContext(); Uri defaultRingtoneUri = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE); assumeNotNull(defaultRingtoneUri); Uri FAKE_RINGTONE_VIBRATION_URI = defaultRingtoneUri.buildUpon().appendQueryParameter( VIBRATION_PARAM, FAKE_VIBRATION_URI.toString()).build(); mComponentContextFixture.putBooleanResource( com.android.internal.R.bool.config_ringtoneVibrationSettingsSupported, true); ArgumentCaptor<Boolean> muteHapticChannelCaptor = ArgumentCaptor.forClass(Boolean.class); try { RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, FAKE_RINGTONE_VIBRATION_URI); createRingerUnderTest(); // Needed after mock the config. mRingerUnderTest.startCallWaiting(mockCall1); ensureRingerIsAudible(); enableRampingRinger(); enableVibrationWhenRinging(); assertTrue(startRingingAndWaitForAsync(mockCall2, false)); verify(mockRingtoneFactory, atLeastOnce()).getRingtone(any(Call.class), nullable(VolumeShaper.Configuration.class), muteHapticChannelCaptor.capture()); assertFalse(muteHapticChannelCaptor.getValue()); } finally { // Restore the default ringtone Uri RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, defaultRingtoneUri); } } /** Loading Loading
src/com/android/server/telecom/Ringer.java +22 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.content.res.Resources; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.media.Utils; import android.media.VolumeShaper; import android.media.audio.Flags; Loading Loading @@ -431,6 +432,11 @@ public class Ringer { && isVibratorEnabled) { Log.i(this, "Muted haptic channels since audio coupled ramping ringer is disabled"); hapticChannelsMuted = true; if (useCustomVibration(foregroundCall)) { Log.i(this, "Not muted haptic channel for customization when apply ramping ringer"); hapticChannelsMuted = false; } } else if (hapticChannelsMuted) { Log.i(this, "Muted haptic channels isVibratorEnabled=%s, hapticPlaybackSupported=%s", Loading @@ -442,7 +448,7 @@ public class Ringer { if (!isHapticOnly) { ringtoneInfoSupplier = () -> mRingtoneFactory.getRingtone( foregroundCall, mVolumeShaperConfig, finalHapticChannelsMuted); } else if (Flags.enableRingtoneHapticsCustomization() && mRingtoneVibrationSupported) { } else if (useCustomVibration(foregroundCall)) { ringtoneInfoSupplier = () -> mRingtoneFactory.getRingtone( foregroundCall, null, false); } Loading Loading @@ -521,6 +527,21 @@ public class Ringer { } } private boolean useCustomVibration(@NonNull Call foregroundCall) { return Flags.enableRingtoneHapticsCustomization() && mRingtoneVibrationSupported && hasExplicitVibration(foregroundCall); } private boolean hasExplicitVibration(@NonNull Call foregroundCall) { final Uri ringtoneUri = foregroundCall.getRingtone(); if (ringtoneUri != null) { // TODO(b/399265235) : Avoid this hidden API access for mainline return Utils.hasVibration(ringtoneUri); } return Utils.hasVibration(RingtoneManager.getActualDefaultRingtoneUri( mContext, RingtoneManager.TYPE_RINGTONE)); } /** * Try to reserve the vibrator for this call, returning false if it's already committed. * The vibration will be started by AsyncRingtonePlayer to ensure timing is aligned with the Loading
tests/src/com/android/server/telecom/tests/RingerTest.java +63 −15 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; Loading @@ -46,6 +47,7 @@ import android.content.Context; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.media.VolumeShaper; import android.media.audio.Flags; import android.net.Uri; Loading @@ -65,6 +67,7 @@ import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.util.Pair; import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; Loading @@ -85,6 +88,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Spy; Loading Loading @@ -846,8 +850,12 @@ public class RingerTest extends TelecomTestCase { @Test @EnableFlags(Flags.FLAG_ENABLE_RINGTONE_HAPTICS_CUSTOMIZATION) public void testNoVibrateForSilentRingtoneIfRingtoneHasVibration() throws Exception { final Context context = ApplicationProvider.getApplicationContext(); Uri defaultRingtoneUri = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE); assumeNotNull(defaultRingtoneUri); Uri FAKE_RINGTONE_VIBRATION_URI = FAKE_RINGTONE_URI.buildUpon().appendQueryParameter( defaultRingtoneUri.buildUpon().appendQueryParameter( VIBRATION_PARAM, FAKE_VIBRATION_URI.toString()).build(); Ringtone mockRingtone = mock(Ringtone.class); Pair<Uri, Ringtone> ringtoneInfo = new Pair(FAKE_RINGTONE_VIBRATION_URI, mockRingtone); Loading @@ -856,6 +864,9 @@ public class RingerTest extends TelecomTestCase { .thenReturn(ringtoneInfo); mComponentContextFixture.putBooleanResource( com.android.internal.R.bool.config_ringtoneVibrationSettingsSupported, true); try { RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, FAKE_RINGTONE_VIBRATION_URI); createRingerUnderTest(); // Needed after mock the config. mRingerUnderTest.startCallWaiting(mockCall1); Loading @@ -871,6 +882,43 @@ public class RingerTest extends TelecomTestCase { // Skip vibration play in Ringer if a vibration was specified to the ringtone verify(mockVibrator, never()).vibrate(any(VibrationEffect.class), any(VibrationAttributes.class)); } finally { // Restore the default ringtone Uri RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, defaultRingtoneUri); } } @SmallTest @Test @EnableFlags(Flags.FLAG_ENABLE_RINGTONE_HAPTICS_CUSTOMIZATION) public void testNotMuteHapticChannelWithRampingRinger() throws Exception { final Context context = ApplicationProvider.getApplicationContext(); Uri defaultRingtoneUri = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE); assumeNotNull(defaultRingtoneUri); Uri FAKE_RINGTONE_VIBRATION_URI = defaultRingtoneUri.buildUpon().appendQueryParameter( VIBRATION_PARAM, FAKE_VIBRATION_URI.toString()).build(); mComponentContextFixture.putBooleanResource( com.android.internal.R.bool.config_ringtoneVibrationSettingsSupported, true); ArgumentCaptor<Boolean> muteHapticChannelCaptor = ArgumentCaptor.forClass(Boolean.class); try { RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, FAKE_RINGTONE_VIBRATION_URI); createRingerUnderTest(); // Needed after mock the config. mRingerUnderTest.startCallWaiting(mockCall1); ensureRingerIsAudible(); enableRampingRinger(); enableVibrationWhenRinging(); assertTrue(startRingingAndWaitForAsync(mockCall2, false)); verify(mockRingtoneFactory, atLeastOnce()).getRingtone(any(Call.class), nullable(VolumeShaper.Configuration.class), muteHapticChannelCaptor.capture()); assertFalse(muteHapticChannelCaptor.getValue()); } finally { // Restore the default ringtone Uri RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, defaultRingtoneUri); } } /** Loading