Loading src/com/android/server/telecom/AsyncRingtonePlayer.java +13 −4 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ package com.android.server.telecom; import android.annotation.Nullable; import android.media.Ringtone; import android.media.VolumeShaper; import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; Loading Loading @@ -67,15 +69,22 @@ public class AsyncRingtonePlayer { mShouldPauseBetweenRepeat = shouldPauseBetweenRepeat; } /** Plays the ringtone. */ public void play(RingtoneFactory factory, Call incomingCall) { /** Plays the ringtone with ramping ringer if required. */ public void play(RingtoneFactory factory, Call incomingCall, @Nullable VolumeShaper.Configuration volumeShaperConfig) { Log.d(this, "Posting play."); SomeArgs args = SomeArgs.obtain(); args.arg1 = factory; args.arg2 = incomingCall; args.arg3 = volumeShaperConfig; postMessage(EVENT_PLAY, true /* shouldCreateHandler */, args); } /** Plays the ringtone. */ public void play(RingtoneFactory factory, Call incomingCall) { play(factory, incomingCall, null); } /** Stops playing the ringtone. */ public void stop() { Log.d(this, "Posting stop."); Loading Loading @@ -136,6 +145,7 @@ public class AsyncRingtonePlayer { private void handlePlay(SomeArgs args) { RingtoneFactory factory = (RingtoneFactory) args.arg1; Call incomingCall = (Call) args.arg2; VolumeShaper.Configuration volumeShaperConfig = (VolumeShaper.Configuration) args.arg3; args.recycle(); // don't bother with any of this if there is an EVENT_STOP waiting. if (mHandler.hasMessages(EVENT_STOP)) { Loading @@ -153,7 +163,7 @@ public class AsyncRingtonePlayer { Log.i(this, "Play ringtone."); if (mRingtone == null) { mRingtone = factory.getRingtone(incomingCall); mRingtone = factory.getRingtone(incomingCall, volumeShaperConfig); if (mRingtone == null) { Uri ringtoneUri = incomingCall.getRingtone(); String ringtoneUriString = (ringtoneUri == null) ? "null" : Loading Loading @@ -183,7 +193,6 @@ public class AsyncRingtonePlayer { if (mRingtone == null) { return; } if (mRingtone.isPlaying()) { Log.d(this, "Ringtone already playing."); } else { Loading src/com/android/server/telecom/Ringer.java +27 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.telecom.TelecomManager; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.VolumeShaper; import android.net.Uri; import android.os.Bundle; import android.os.Vibrator; Loading Loading @@ -82,11 +83,17 @@ public class Ringer { private static final int REPEAT_SIMPLE_VIBRATION_AT = 1; private static final int DEFAULT_RAMPING_RINGER_DURATION = 15000; // 15 seconds private static int rampingRingerDuration = -1; private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) .build(); private static VolumeShaper.Configuration volumeShaperConfig; /** * Used to keep ordering of unanswered incoming calls. There can easily exist multiple incoming * calls and explicit ordering is useful for maintaining the proper state of the ringer. Loading Loading @@ -197,7 +204,26 @@ public class Ringer { // call (for the purposes of direct-to-voicemail), the information about custom // ringtones should be available by the time this code executes. We can safely // request the custom ringtone from the call and expect it to be current. mRingtonePlayer.play(mRingtoneFactory, foregroundCall); if (mSystemSettingsUtil.applyRampingRinger(mContext) || mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()) { Log.i(this, "start ramping ringer."); int previousRampingRingerDuration = rampingRingerDuration; rampingRingerDuration = mSystemSettingsUtil.getRampingRingerDuration() > 0 ? mSystemSettingsUtil.getRampingRingerDuration() : DEFAULT_RAMPING_RINGER_DURATION; if ((rampingRingerDuration != previousRampingRingerDuration) || volumeShaperConfig == null) { volumeShaperConfig = new VolumeShaper.Configuration.Builder() .setDuration(rampingRingerDuration) .setCurve(new float[] {0.f, 1.f}, new float[] {0.f, 1.f}) .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR) .build(); } mRingtonePlayer.play(mRingtoneFactory, foregroundCall, volumeShaperConfig); } else { mRingtonePlayer.play(mRingtoneFactory, foregroundCall, null); } effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall); } else { String reason = String.format( Loading src/com/android/server/telecom/RingtoneFactory.java +11 −3 Original line number Diff line number Diff line Loading @@ -16,12 +16,14 @@ package com.android.server.telecom; import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.media.AudioManager; import android.media.RingtoneManager; import android.media.Ringtone; import android.media.VolumeShaper; import android.net.Uri; import android.os.UserHandle; import android.os.UserManager; Loading Loading @@ -52,7 +54,8 @@ public class RingtoneFactory { mCallsManager = callsManager; } public Ringtone getRingtone(Call incomingCall) { public Ringtone getRingtone(Call incomingCall, @Nullable VolumeShaper.Configuration volumeShaperConfig) { // Use the default ringtone of the work profile if the contact is a work profile contact. Context userContext = isWorkContact(incomingCall) ? getWorkProfileContextForUser(mCallsManager.getCurrentUserHandle()) : Loading @@ -62,7 +65,7 @@ public class RingtoneFactory { if(ringtoneUri != null && userContext != null) { // Ringtone URI is explicitly specified. First, try to create a Ringtone with that. ringtone = RingtoneManager.getRingtone(userContext, ringtoneUri); ringtone = RingtoneManager.getRingtone(userContext, ringtoneUri, volumeShaperConfig); } if(ringtone == null) { // Contact didn't specify ringtone or custom Ringtone creation failed. Get default Loading @@ -78,7 +81,8 @@ public class RingtoneFactory { if (defaultRingtoneUri == null) { return null; } ringtone = RingtoneManager.getRingtone(contextToUse, defaultRingtoneUri); ringtone = RingtoneManager.getRingtone( contextToUse, defaultRingtoneUri, volumeShaperConfig); } if (ringtone != null) { ringtone.setStreamType(AudioManager.STREAM_RING); Loading @@ -86,6 +90,10 @@ public class RingtoneFactory { return ringtone; } public Ringtone getRingtone(Call incomingCall) { return getRingtone(incomingCall, null); } private Context getWorkProfileContextForUser(UserHandle userHandle) { // UserManager.getEnabledProfiles returns the enabled profiles along with the user's handle // itself (so we must filter out the user). Loading src/com/android/server/telecom/SystemSettingsUtil.java +42 −0 Original line number Diff line number Diff line Loading @@ -17,7 +17,9 @@ package com.android.server.telecom; import android.content.Context; import android.provider.DeviceConfig; import android.provider.Settings; import android.telecom.Log; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -46,4 +48,44 @@ public class SystemSettingsUtil { return Settings.System.putInt(context.getContentResolver(), Settings.System.DEBUG_ENABLE_ENHANCED_CALL_BLOCKING, enabled ? 1 : 0); } public boolean applyRampingRinger(Context context) { return Settings.Global.getInt(context.getContentResolver(), Settings.Global.APPLY_RAMPING_RINGER, 0) == 1; } public boolean enableRampingRingerFromDeviceConfig() { String enableRampingRinger = DeviceConfig.getProperty( DeviceConfig.Telephony.NAMESPACE, DeviceConfig.Telephony.PROPERTY_ENABLE_RAMPING_RINGER); if (enableRampingRinger == null) { Log.i(this, "DeviceConfig.Telephony.PROPERTY_ENABLE_RAMPING_RINGER is null"); return false; } try { return Boolean.valueOf(enableRampingRinger); } catch (Exception e) { Log.wtf(this, "Error paring DeviceConfig.Telephony.PROPERTY_ENABLE_RAMPING_RINGER: " + e); return false; } } public int getRampingRingerDuration() { String rampingRingerDuration = DeviceConfig.getProperty( DeviceConfig.Telephony.NAMESPACE, DeviceConfig.Telephony.PROPERTY_RAMPING_RINGER_DURATION); if (rampingRingerDuration == null) { Log.i(this, "DeviceConfig.Telephony.PROPERTY_RAMPING_RINGER_DURATION is null"); return -1; } try { return Integer.parseInt(rampingRingerDuration); } catch (Exception e) { Log.wtf(this, "Error paring DeviceConfig.Telephony.PROPERTY_RAMPING_RINGER_DURATION: " + e); return -1; } } } tests/src/com/android/server/telecom/tests/RingerTest.java +19 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.content.Context; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.VolumeShaper; import android.net.Uri; import android.os.Bundle; import android.os.Parcel; Loading Loading @@ -257,7 +258,7 @@ public class RingerTest extends TelecomTestCase { enableVibrationWhenRinging(); assertTrue(mRingerUnderTest.startRinging(mockCall2, false)); verify(mockTonePlayer).stopTone(); verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class)); verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), eq(null)); verify(mockVibrator).vibrate(eq(spyVibrationEffectProxy.get(FAKE_RINGTONE_URI, mContext)), any(AudioAttributes.class)); } Loading @@ -270,11 +271,23 @@ public class RingerTest extends TelecomTestCase { enableVibrationOnlyWhenNotRinging(); assertTrue(mRingerUnderTest.startRinging(mockCall2, false)); verify(mockTonePlayer).stopTone(); verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class)); verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), eq(null)); verify(mockVibrator, never()) .vibrate(any(VibrationEffect.class), any(AudioAttributes.class)); } @SmallTest @Test public void testRingWithRampingRinger() { mRingerUnderTest.startCallWaiting(mockCall1); ensureRingerIsAudible(); enableRampingRinger(); assertTrue(mRingerUnderTest.startRinging(mockCall2, false)); verify(mockTonePlayer).stopTone(); verify(mockRingtonePlayer).play( any(RingtoneFactory.class), any(Call.class), any(VolumeShaper.Configuration.class)); } @SmallTest @Test public void testSilentRingWithHfpStillAcquiresFocus1() { Loading Loading @@ -322,4 +335,8 @@ public class RingerTest extends TelecomTestCase { when(mockVibrator.hasVibrator()).thenReturn(true); when(mockSystemSettingsUtil.canVibrateWhenRinging(any(Context.class))).thenReturn(false); } private void enableRampingRinger() { when(mockSystemSettingsUtil.applyRampingRinger(any(Context.class))).thenReturn(true); } } Loading
src/com/android/server/telecom/AsyncRingtonePlayer.java +13 −4 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ package com.android.server.telecom; import android.annotation.Nullable; import android.media.Ringtone; import android.media.VolumeShaper; import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; Loading Loading @@ -67,15 +69,22 @@ public class AsyncRingtonePlayer { mShouldPauseBetweenRepeat = shouldPauseBetweenRepeat; } /** Plays the ringtone. */ public void play(RingtoneFactory factory, Call incomingCall) { /** Plays the ringtone with ramping ringer if required. */ public void play(RingtoneFactory factory, Call incomingCall, @Nullable VolumeShaper.Configuration volumeShaperConfig) { Log.d(this, "Posting play."); SomeArgs args = SomeArgs.obtain(); args.arg1 = factory; args.arg2 = incomingCall; args.arg3 = volumeShaperConfig; postMessage(EVENT_PLAY, true /* shouldCreateHandler */, args); } /** Plays the ringtone. */ public void play(RingtoneFactory factory, Call incomingCall) { play(factory, incomingCall, null); } /** Stops playing the ringtone. */ public void stop() { Log.d(this, "Posting stop."); Loading Loading @@ -136,6 +145,7 @@ public class AsyncRingtonePlayer { private void handlePlay(SomeArgs args) { RingtoneFactory factory = (RingtoneFactory) args.arg1; Call incomingCall = (Call) args.arg2; VolumeShaper.Configuration volumeShaperConfig = (VolumeShaper.Configuration) args.arg3; args.recycle(); // don't bother with any of this if there is an EVENT_STOP waiting. if (mHandler.hasMessages(EVENT_STOP)) { Loading @@ -153,7 +163,7 @@ public class AsyncRingtonePlayer { Log.i(this, "Play ringtone."); if (mRingtone == null) { mRingtone = factory.getRingtone(incomingCall); mRingtone = factory.getRingtone(incomingCall, volumeShaperConfig); if (mRingtone == null) { Uri ringtoneUri = incomingCall.getRingtone(); String ringtoneUriString = (ringtoneUri == null) ? "null" : Loading Loading @@ -183,7 +193,6 @@ public class AsyncRingtonePlayer { if (mRingtone == null) { return; } if (mRingtone.isPlaying()) { Log.d(this, "Ringtone already playing."); } else { Loading
src/com/android/server/telecom/Ringer.java +27 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.telecom.TelecomManager; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.VolumeShaper; import android.net.Uri; import android.os.Bundle; import android.os.Vibrator; Loading Loading @@ -82,11 +83,17 @@ public class Ringer { private static final int REPEAT_SIMPLE_VIBRATION_AT = 1; private static final int DEFAULT_RAMPING_RINGER_DURATION = 15000; // 15 seconds private static int rampingRingerDuration = -1; private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) .build(); private static VolumeShaper.Configuration volumeShaperConfig; /** * Used to keep ordering of unanswered incoming calls. There can easily exist multiple incoming * calls and explicit ordering is useful for maintaining the proper state of the ringer. Loading Loading @@ -197,7 +204,26 @@ public class Ringer { // call (for the purposes of direct-to-voicemail), the information about custom // ringtones should be available by the time this code executes. We can safely // request the custom ringtone from the call and expect it to be current. mRingtonePlayer.play(mRingtoneFactory, foregroundCall); if (mSystemSettingsUtil.applyRampingRinger(mContext) || mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()) { Log.i(this, "start ramping ringer."); int previousRampingRingerDuration = rampingRingerDuration; rampingRingerDuration = mSystemSettingsUtil.getRampingRingerDuration() > 0 ? mSystemSettingsUtil.getRampingRingerDuration() : DEFAULT_RAMPING_RINGER_DURATION; if ((rampingRingerDuration != previousRampingRingerDuration) || volumeShaperConfig == null) { volumeShaperConfig = new VolumeShaper.Configuration.Builder() .setDuration(rampingRingerDuration) .setCurve(new float[] {0.f, 1.f}, new float[] {0.f, 1.f}) .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR) .build(); } mRingtonePlayer.play(mRingtoneFactory, foregroundCall, volumeShaperConfig); } else { mRingtonePlayer.play(mRingtoneFactory, foregroundCall, null); } effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall); } else { String reason = String.format( Loading
src/com/android/server/telecom/RingtoneFactory.java +11 −3 Original line number Diff line number Diff line Loading @@ -16,12 +16,14 @@ package com.android.server.telecom; import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.media.AudioManager; import android.media.RingtoneManager; import android.media.Ringtone; import android.media.VolumeShaper; import android.net.Uri; import android.os.UserHandle; import android.os.UserManager; Loading Loading @@ -52,7 +54,8 @@ public class RingtoneFactory { mCallsManager = callsManager; } public Ringtone getRingtone(Call incomingCall) { public Ringtone getRingtone(Call incomingCall, @Nullable VolumeShaper.Configuration volumeShaperConfig) { // Use the default ringtone of the work profile if the contact is a work profile contact. Context userContext = isWorkContact(incomingCall) ? getWorkProfileContextForUser(mCallsManager.getCurrentUserHandle()) : Loading @@ -62,7 +65,7 @@ public class RingtoneFactory { if(ringtoneUri != null && userContext != null) { // Ringtone URI is explicitly specified. First, try to create a Ringtone with that. ringtone = RingtoneManager.getRingtone(userContext, ringtoneUri); ringtone = RingtoneManager.getRingtone(userContext, ringtoneUri, volumeShaperConfig); } if(ringtone == null) { // Contact didn't specify ringtone or custom Ringtone creation failed. Get default Loading @@ -78,7 +81,8 @@ public class RingtoneFactory { if (defaultRingtoneUri == null) { return null; } ringtone = RingtoneManager.getRingtone(contextToUse, defaultRingtoneUri); ringtone = RingtoneManager.getRingtone( contextToUse, defaultRingtoneUri, volumeShaperConfig); } if (ringtone != null) { ringtone.setStreamType(AudioManager.STREAM_RING); Loading @@ -86,6 +90,10 @@ public class RingtoneFactory { return ringtone; } public Ringtone getRingtone(Call incomingCall) { return getRingtone(incomingCall, null); } private Context getWorkProfileContextForUser(UserHandle userHandle) { // UserManager.getEnabledProfiles returns the enabled profiles along with the user's handle // itself (so we must filter out the user). Loading
src/com/android/server/telecom/SystemSettingsUtil.java +42 −0 Original line number Diff line number Diff line Loading @@ -17,7 +17,9 @@ package com.android.server.telecom; import android.content.Context; import android.provider.DeviceConfig; import android.provider.Settings; import android.telecom.Log; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -46,4 +48,44 @@ public class SystemSettingsUtil { return Settings.System.putInt(context.getContentResolver(), Settings.System.DEBUG_ENABLE_ENHANCED_CALL_BLOCKING, enabled ? 1 : 0); } public boolean applyRampingRinger(Context context) { return Settings.Global.getInt(context.getContentResolver(), Settings.Global.APPLY_RAMPING_RINGER, 0) == 1; } public boolean enableRampingRingerFromDeviceConfig() { String enableRampingRinger = DeviceConfig.getProperty( DeviceConfig.Telephony.NAMESPACE, DeviceConfig.Telephony.PROPERTY_ENABLE_RAMPING_RINGER); if (enableRampingRinger == null) { Log.i(this, "DeviceConfig.Telephony.PROPERTY_ENABLE_RAMPING_RINGER is null"); return false; } try { return Boolean.valueOf(enableRampingRinger); } catch (Exception e) { Log.wtf(this, "Error paring DeviceConfig.Telephony.PROPERTY_ENABLE_RAMPING_RINGER: " + e); return false; } } public int getRampingRingerDuration() { String rampingRingerDuration = DeviceConfig.getProperty( DeviceConfig.Telephony.NAMESPACE, DeviceConfig.Telephony.PROPERTY_RAMPING_RINGER_DURATION); if (rampingRingerDuration == null) { Log.i(this, "DeviceConfig.Telephony.PROPERTY_RAMPING_RINGER_DURATION is null"); return -1; } try { return Integer.parseInt(rampingRingerDuration); } catch (Exception e) { Log.wtf(this, "Error paring DeviceConfig.Telephony.PROPERTY_RAMPING_RINGER_DURATION: " + e); return -1; } } }
tests/src/com/android/server/telecom/tests/RingerTest.java +19 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.content.Context; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.VolumeShaper; import android.net.Uri; import android.os.Bundle; import android.os.Parcel; Loading Loading @@ -257,7 +258,7 @@ public class RingerTest extends TelecomTestCase { enableVibrationWhenRinging(); assertTrue(mRingerUnderTest.startRinging(mockCall2, false)); verify(mockTonePlayer).stopTone(); verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class)); verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), eq(null)); verify(mockVibrator).vibrate(eq(spyVibrationEffectProxy.get(FAKE_RINGTONE_URI, mContext)), any(AudioAttributes.class)); } Loading @@ -270,11 +271,23 @@ public class RingerTest extends TelecomTestCase { enableVibrationOnlyWhenNotRinging(); assertTrue(mRingerUnderTest.startRinging(mockCall2, false)); verify(mockTonePlayer).stopTone(); verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class)); verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), eq(null)); verify(mockVibrator, never()) .vibrate(any(VibrationEffect.class), any(AudioAttributes.class)); } @SmallTest @Test public void testRingWithRampingRinger() { mRingerUnderTest.startCallWaiting(mockCall1); ensureRingerIsAudible(); enableRampingRinger(); assertTrue(mRingerUnderTest.startRinging(mockCall2, false)); verify(mockTonePlayer).stopTone(); verify(mockRingtonePlayer).play( any(RingtoneFactory.class), any(Call.class), any(VolumeShaper.Configuration.class)); } @SmallTest @Test public void testSilentRingWithHfpStillAcquiresFocus1() { Loading Loading @@ -322,4 +335,8 @@ public class RingerTest extends TelecomTestCase { when(mockVibrator.hasVibrator()).thenReturn(true); when(mockSystemSettingsUtil.canVibrateWhenRinging(any(Context.class))).thenReturn(false); } private void enableRampingRinger() { when(mockSystemSettingsUtil.applyRampingRinger(any(Context.class))).thenReturn(true); } }