Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 435bafcb authored by Yiwen Chen's avatar Yiwen Chen
Browse files

Fix ramping ringer duration naming and add vibration function

Bug: 120789399
Test: Test on device
Change-Id: I494eaccc6cfe451d439edb3e473eb70cef8fd4c7
parent 7e91d89e
Loading
Loading
Loading
Loading
+109 −22
Original line number Diff line number Diff line
@@ -32,8 +32,12 @@ import android.os.Bundle;
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 @@ public class Ringer {
    @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 @@ 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 final int DEFAULT_RAMPING_RINGER_DURATION = 10000;  // 10 seconds

    private int mRampingRingerDuration = -1;  // ramping ringer duration in millisecond

    private static int rampingRingerDuration = -1;
    // 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 @@ public class Ringer {
            // 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);
            }
        } else {
            String reason = String.format(
                    "isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s",
@@ -234,7 +285,15 @@ public class Ringer {
            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 @@ public class Ringer {
        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);
+24 −6
Original line number Diff line number Diff line
@@ -57,16 +57,16 @@ public class SystemSettingsUtil {
    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 class SystemSettingsUtil {
    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;
        }
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -282,6 +282,7 @@ public class RingerTest extends TelecomTestCase {
        mRingerUnderTest.startCallWaiting(mockCall1);
        ensureRingerIsAudible();
        enableRampingRinger();
        enableRampingRingerFromDeviceConfig();
        assertTrue(mRingerUnderTest.startRinging(mockCall2, false));
        verify(mockTonePlayer).stopTone();
        verify(mockRingtonePlayer).play(
@@ -339,4 +340,8 @@ public class RingerTest extends TelecomTestCase {
    private void enableRampingRinger() {
        when(mockSystemSettingsUtil.applyRampingRinger(any(Context.class))).thenReturn(true);
    }

    private void enableRampingRingerFromDeviceConfig() {
        when(mockSystemSettingsUtil.enableRampingRingerFromDeviceConfig()).thenReturn(true);
    }
}