Merge "Fix ramping ringer duration naming and add vibration function"
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index 5d5f1bb..1eaf249 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -32,8 +32,12 @@
import android.os.Vibrator;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
/**
* Controls the ringtone player.
@@ -52,15 +56,37 @@
@VisibleForTesting
public VibrationEffect mDefaultVibrationEffect;
- private static final long[] PULSE_PATTERN = {0,12,250,12,500, // priming + interval
- 50,50,50,50,50,50,50,50,50,50,50,50,50,50, // ease-in
- 300, // Peak
- 1000}; // pause before repetition
+ private static final long[] PULSE_PRIMING_PATTERN = {0,12,250,12,500}; // priming + interval
- private static final int[] PULSE_AMPLITUDE = {0,255,0,255,0, // priming + interval
- 77,77,78,79,81,84,87,93,101,114,133,162,205,255, // ease-in (min amplitude = 30%)
- 255, // Peak
- 0}; // pause before repetition
+ private static final int[] PULSE_PRIMING_AMPLITUDE = {0,255,0,255,0}; // priming + interval
+
+ // ease-in + peak + pause
+ private static final long[] PULSE_RAMPING_PATTERN = {
+ 50,50,50,50,50,50,50,50,50,50,50,50,50,50,300,1000};
+
+ // ease-in (min amplitude = 30%) + peak + pause
+ private static final int[] PULSE_RAMPING_AMPLITUDE = {
+ 77,77,78,79,81,84,87,93,101,114,133,162,205,255,255,0};
+
+ private static final long[] PULSE_PATTERN;
+
+ private static final int[] PULSE_AMPLITUDE;
+
+ static {
+ // construct complete pulse pattern
+ PULSE_PATTERN = new long[PULSE_PRIMING_PATTERN.length + PULSE_RAMPING_PATTERN.length];
+ System.arraycopy(
+ PULSE_PRIMING_PATTERN, 0, PULSE_PATTERN, 0, PULSE_PRIMING_PATTERN.length);
+ System.arraycopy(PULSE_RAMPING_PATTERN, 0, PULSE_PATTERN,
+ PULSE_PRIMING_PATTERN.length, PULSE_RAMPING_PATTERN.length);
+
+ // construct complete pulse amplitude
+ PULSE_AMPLITUDE = new int[PULSE_PRIMING_AMPLITUDE.length + PULSE_RAMPING_AMPLITUDE.length];
+ System.arraycopy(
+ PULSE_PRIMING_AMPLITUDE, 0, PULSE_AMPLITUDE, 0, PULSE_PRIMING_AMPLITUDE.length);
+ System.arraycopy(PULSE_RAMPING_AMPLITUDE, 0, PULSE_AMPLITUDE,
+ PULSE_PRIMING_AMPLITUDE.length, PULSE_RAMPING_AMPLITUDE.length);
+ }
private static final long[] SIMPLE_VIBRATION_PATTERN = {
0, // No delay before starting
@@ -83,16 +109,22 @@
private static final int REPEAT_SIMPLE_VIBRATION_AT = 1;
- private static final int DEFAULT_RAMPING_RINGER_DURATION = 15000; // 15 seconds
+ private static final int DEFAULT_RAMPING_RINGER_DURATION = 10000; // 10 seconds
- private static int rampingRingerDuration = -1;
+ private int mRampingRingerDuration = -1; // ramping ringer duration in millisecond
+
+ // vibration duration before ramping ringer in second
+ private int mRampingRingerVibrationDuration = 0;
+
+ private static final float EPSILON = 1e-6f;
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;
+ private static VibrationEffect mRampingRingerVibrationEffect;
+ private static VolumeShaper.Configuration mVolumeShaperConfig;
/**
* Used to keep ordering of unanswered incoming calls. There can easily exist multiple incoming
@@ -205,26 +237,45 @@
// 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.
if (mSystemSettingsUtil.applyRampingRinger(mContext)
- || mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()) {
+ && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()) {
Log.i(this, "start ramping ringer.");
- int previousRampingRingerDuration = rampingRingerDuration;
- rampingRingerDuration =
+ // configure vibration effect for ramping ringer.
+ int previousRampingRingerVibrationDuration = mRampingRingerVibrationDuration;
+ // get vibration duration in millisecond and round down to second.
+ mRampingRingerVibrationDuration =
+ mSystemSettingsUtil.getRampingRingerVibrationDuration() >= 0
+ ? mSystemSettingsUtil.getRampingRingerVibrationDuration() / 1000
+ : 0;
+ if (mRampingRingerVibrationDuration != previousRampingRingerVibrationDuration) {
+ mRampingRingerVibrationEffect =
+ createRampingRingerVibrationEffect(mRampingRingerVibrationDuration);
+ }
+ effect = mRampingRingerVibrationEffect;
+
+ // configure volume shaper for ramping ringer
+ int previousRampingRingerDuration = mRampingRingerDuration;
+ mRampingRingerDuration =
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})
+ if (mRampingRingerDuration != previousRampingRingerDuration
+ || mRampingRingerVibrationDuration != previousRampingRingerVibrationDuration
+ || mVolumeShaperConfig == null) {
+ float silencePoint = (float) (mRampingRingerVibrationDuration * 1000)
+ / (float) (mRampingRingerVibrationDuration * 1000 + mRampingRingerDuration);
+ mVolumeShaperConfig = new VolumeShaper.Configuration.Builder()
+ .setDuration(mRampingRingerVibrationDuration * 1000
+ + mRampingRingerDuration)
+ .setCurve(new float[] {0.f, silencePoint + EPSILON /*keep monotonicity*/,
+ 1.f}, new float[] {0.f, 0.f, 1.f})
.setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
.build();
}
- mRingtonePlayer.play(mRingtoneFactory, foregroundCall, volumeShaperConfig);
+ mRingtonePlayer.play(mRingtoneFactory, foregroundCall, mVolumeShaperConfig);
} else {
mRingtonePlayer.play(mRingtoneFactory, foregroundCall, null);
+ effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall);
}
- effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall);
} else {
String reason = String.format(
"isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s",
@@ -234,7 +285,15 @@
effect = mDefaultVibrationEffect;
}
- if (shouldVibrate(mContext, foregroundCall) && !mIsVibrating && shouldRingForContact) {
+ if (mSystemSettingsUtil.applyRampingRinger(mContext)
+ && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()
+ && effect != null) {
+ Log.i(this, "start vibration for ramping ringer.");
+ mVibrator.vibrate(effect);
+ mIsVibrating = true;
+ } else if (shouldVibrate(mContext, foregroundCall)
+ && !mIsVibrating && shouldRingForContact) {
+ Log.i(this, "start normal vibration.");
mVibrator.vibrate(effect, VIBRATION_ATTRIBUTES);
mIsVibrating = true;
} else if (mIsVibrating) {
@@ -244,6 +303,34 @@
return shouldAcquireAudioFocus;
}
+ private VibrationEffect createRampingRingerVibrationEffect(int vibrationSeconds) {
+ if (vibrationSeconds < 1) { // vibration duration has to be at least 1 second long.
+ return null;
+ }
+ List<Long> rampingRingerVibrationPatternList = new ArrayList<>();
+ List<Integer> rampingRingerVibrationAmplitudeList = new ArrayList<>();
+ while (vibrationSeconds > 0) {
+ rampingRingerVibrationPatternList.addAll(
+ Arrays.stream(PULSE_RAMPING_PATTERN).boxed().collect(Collectors.toList()));
+ rampingRingerVibrationAmplitudeList.addAll(
+ Arrays.stream(PULSE_RAMPING_AMPLITUDE).boxed().collect(Collectors.toList()));
+ vibrationSeconds -= 2;
+ }
+ // remove the last second of pause
+ if (vibrationSeconds < 0) {
+ rampingRingerVibrationPatternList.remove(
+ rampingRingerVibrationPatternList.size() - 1);
+ rampingRingerVibrationAmplitudeList.remove(
+ rampingRingerVibrationAmplitudeList.size() - 1);
+ }
+ long[] rampingRingerVibrationPatternArray =
+ rampingRingerVibrationPatternList.stream().mapToLong(i -> i).toArray();
+ int[] rampingRingerVibrationAmplitudeArray =
+ rampingRingerVibrationAmplitudeList.stream().mapToInt(i -> i).toArray();
+ return VibrationEffect.createWaveform(rampingRingerVibrationPatternArray,
+ rampingRingerVibrationAmplitudeArray, -1 /* not repeat */);
+ }
+
private VibrationEffect getVibrationEffectForCall(RingtoneFactory factory, Call call) {
VibrationEffect effect = null;
Ringtone ringtone = factory.getRingtone(call);
diff --git a/src/com/android/server/telecom/SystemSettingsUtil.java b/src/com/android/server/telecom/SystemSettingsUtil.java
index cef5f70..c80d327 100644
--- a/src/com/android/server/telecom/SystemSettingsUtil.java
+++ b/src/com/android/server/telecom/SystemSettingsUtil.java
@@ -57,16 +57,16 @@
public boolean enableRampingRingerFromDeviceConfig() {
String enableRampingRinger = DeviceConfig.getProperty(
DeviceConfig.Telephony.NAMESPACE,
- DeviceConfig.Telephony.PROPERTY_ENABLE_RAMPING_RINGER);
+ DeviceConfig.Telephony.RAMPING_RINGER_ENABLED);
if (enableRampingRinger == null) {
- Log.i(this, "DeviceConfig.Telephony.PROPERTY_ENABLE_RAMPING_RINGER is null");
+ Log.i(this, "Telephony.RAMPING_RINGER_ENABLED is null");
return false;
}
try {
return Boolean.valueOf(enableRampingRinger);
} catch (Exception e) {
Log.wtf(this,
- "Error paring DeviceConfig.Telephony.PROPERTY_ENABLE_RAMPING_RINGER: " + e);
+ "Error parsing Telephony.RAMPING_RINGER_ENABLED: " + e);
return false;
}
}
@@ -74,18 +74,36 @@
public int getRampingRingerDuration() {
String rampingRingerDuration = DeviceConfig.getProperty(
DeviceConfig.Telephony.NAMESPACE,
- DeviceConfig.Telephony.PROPERTY_RAMPING_RINGER_DURATION);
+ DeviceConfig.Telephony.RAMPING_RINGER_DURATION);
if (rampingRingerDuration == null) {
- Log.i(this, "DeviceConfig.Telephony.PROPERTY_RAMPING_RINGER_DURATION is null");
+ Log.i(this, "Telephony.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);
+ "Error parsing Telephony.RAMPING_RINGER_DURATION: " + e);
return -1;
}
}
+
+ public int getRampingRingerVibrationDuration() {
+ String rampingRingerVibrationDuration = DeviceConfig.getProperty(
+ DeviceConfig.Telephony.NAMESPACE,
+ DeviceConfig.Telephony.RAMPING_RINGER_VIBRATION_DURATION);
+ if (rampingRingerVibrationDuration == null) {
+ Log.i(this,
+ "Telephony.RAMPING_RINGER_VIBRATION_DURATION is null");
+ return 0;
+ }
+ try {
+ return Integer.parseInt(rampingRingerVibrationDuration);
+ } catch (Exception e) {
+ Log.wtf(this,
+ "Error parsing Telephony.RAMPING_RINGER_VIBRATION_DURATION: " + e);
+ return 0;
+ }
+ }
}
diff --git a/tests/src/com/android/server/telecom/tests/RingerTest.java b/tests/src/com/android/server/telecom/tests/RingerTest.java
index 9c43e2b..47bc464 100644
--- a/tests/src/com/android/server/telecom/tests/RingerTest.java
+++ b/tests/src/com/android/server/telecom/tests/RingerTest.java
@@ -282,6 +282,7 @@
mRingerUnderTest.startCallWaiting(mockCall1);
ensureRingerIsAudible();
enableRampingRinger();
+ enableRampingRingerFromDeviceConfig();
assertTrue(mRingerUnderTest.startRinging(mockCall2, false));
verify(mockTonePlayer).stopTone();
verify(mockRingtonePlayer).play(
@@ -339,4 +340,8 @@
private void enableRampingRinger() {
when(mockSystemSettingsUtil.applyRampingRinger(any(Context.class))).thenReturn(true);
}
+
+ private void enableRampingRingerFromDeviceConfig() {
+ when(mockSystemSettingsUtil.enableRampingRingerFromDeviceConfig()).thenReturn(true);
+ }
}