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

Commit 7d2cd434 authored by Yiwen Chen's avatar Yiwen Chen Committed by Android (Google) Code Review
Browse files

Merge "Fix ramping ringer duration naming and add vibration function"

parents 28678047 435bafcb
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);
    }
}