Merge "Move PWLE notification vibration pattern to config.xml" into sc-v2-dev

This commit is contained in:
Lais Andrade
2022-01-13 13:52:55 +00:00
committed by Android (Google) Code Review
4 changed files with 108 additions and 24 deletions

View File

@@ -2679,6 +2679,16 @@
<item>350</item> <item>350</item>
</integer-array> </integer-array>
<!-- A vibration waveform for notifications that specify DEFAULT_VIBRATE.
This value is a float array with values grouped as
{ targetAmplitude (within [0,1]), targetFrequency [-1,1], duration (in milliseconds) }
This is only applied on devices with vibration frequency control. If the device doesn't
support frequency control, then the vibration specified in
config_defaultNotificationVibePattern is used instead.
-->
<array name="config_defaultNotificationVibeWaveform">
</array>
<!-- Vibrator pattern to be used as the default for notifications <!-- Vibrator pattern to be used as the default for notifications
that do not specify vibration but vibrate anyway because the device that do not specify vibration but vibrate anyway because the device
is in vibrate mode. is in vibrate mode.
@@ -2690,6 +2700,16 @@
<item>100</item> <item>100</item>
</integer-array> </integer-array>
<!-- A vibration waveform for notifications that do not specify vibration but vibrate anyway,
because the device is in vibrate mode. This value is a float array with values grouped as
{ targetAmplitude (within [0,1]), targetFrequency [-1,1], duration (in milliseconds) }
This is only applied on devices with vibration frequency control. If the device doesn't
support frequency control, then the vibration specified in
config_notificationFallbackVibePattern is used instead.
-->
<array name="config_notificationFallbackVibeWaveform">
</array>
<!-- Flag indicating if the speed up audio on mt call code should be executed --> <!-- Flag indicating if the speed up audio on mt call code should be executed -->
<bool name="config_speed_up_audio_on_mt_calls">false</bool> <bool name="config_speed_up_audio_on_mt_calls">false</bool>

View File

@@ -1917,7 +1917,9 @@
<java-symbol type="array" name="config_locationExtraPackageNames" /> <java-symbol type="array" name="config_locationExtraPackageNames" />
<java-symbol type="array" name="config_testLocationProviders" /> <java-symbol type="array" name="config_testLocationProviders" />
<java-symbol type="array" name="config_defaultNotificationVibePattern" /> <java-symbol type="array" name="config_defaultNotificationVibePattern" />
<java-symbol type="array" name="config_defaultNotificationVibeWaveform" />
<java-symbol type="array" name="config_notificationFallbackVibePattern" /> <java-symbol type="array" name="config_notificationFallbackVibePattern" />
<java-symbol type="array" name="config_notificationFallbackVibeWaveform" />
<java-symbol type="bool" name="config_enableServerNotificationEffectsForAutomotive" /> <java-symbol type="bool" name="config_enableServerNotificationEffectsForAutomotive" />
<java-symbol type="bool" name="config_useAttentionLight" /> <java-symbol type="bool" name="config_useAttentionLight" />
<java-symbol type="bool" name="config_adaptive_sleep_available" /> <java-symbol type="bool" name="config_adaptive_sleep_available" />

View File

@@ -19,6 +19,7 @@ package com.android.server.notification;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.TypedArray;
import android.media.AudioAttributes; import android.media.AudioAttributes;
import android.os.Process; import android.os.Process;
import android.os.VibrationAttributes; import android.os.VibrationAttributes;
@@ -39,18 +40,16 @@ public final class VibratorHelper {
private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
private static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps private static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
private static final int CHIRP_LEVEL_DURATION_MILLIS = 100;
private static final int DEFAULT_CHIRP_RAMP_DURATION_MILLIS = 100;
private static final int FALLBACK_CHIRP_RAMP_DURATION_MILLIS = 50;
private final Vibrator mVibrator; private final Vibrator mVibrator;
private final long[] mDefaultPattern; private final long[] mDefaultPattern;
private final long[] mFallbackPattern; private final long[] mFallbackPattern;
@Nullable private final float[] mDefaultPwlePattern;
@Nullable private final float[] mFallbackPwlePattern;
public VibratorHelper(Context context) { public VibratorHelper(Context context) {
mVibrator = context.getSystemService(Vibrator.class); mVibrator = context.getSystemService(Vibrator.class);
mDefaultPattern = getLongArray( mDefaultPattern = getLongArray(context.getResources(),
context.getResources(),
com.android.internal.R.array.config_defaultNotificationVibePattern, com.android.internal.R.array.config_defaultNotificationVibePattern,
VIBRATE_PATTERN_MAXLEN, VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN); DEFAULT_VIBRATE_PATTERN);
@@ -58,6 +57,10 @@ public final class VibratorHelper {
R.array.config_notificationFallbackVibePattern, R.array.config_notificationFallbackVibePattern,
VIBRATE_PATTERN_MAXLEN, VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN); DEFAULT_VIBRATE_PATTERN);
mDefaultPwlePattern = getFloatArray(context.getResources(),
com.android.internal.R.array.config_defaultNotificationVibeWaveform);
mFallbackPwlePattern = getFloatArray(context.getResources(),
com.android.internal.R.array.config_notificationFallbackVibeWaveform);
} }
/** /**
@@ -82,6 +85,50 @@ public final class VibratorHelper {
return null; return null;
} }
/**
* Safely create a {@link VibrationEffect} from given waveform description.
*
* <p>The waveform is described by a sequence of values for target amplitude, frequency and
* duration, that are forwarded to
* {@link VibrationEffect.WaveformBuilder#addRamp(float, float, int)}.
*
* <p>This method returns {@code null} if the pattern is also {@code null} or invalid.
*
* @param values The list of values describing the waveform as a sequence of target amplitude,
* frequency and duration.
* @param insistent {@code true} if the vibration should loop until it is cancelled.
*/
@Nullable
public static VibrationEffect createPwleWaveformVibration(@Nullable float[] values,
boolean insistent) {
try {
if (values == null) {
return null;
}
int length = values.length;
// The waveform is described by triples (amplitude, frequency, duration)
if ((length == 0) || (length % 3 != 0)) {
return null;
}
VibrationEffect.WaveformBuilder waveformBuilder = VibrationEffect.startWaveform();
for (int i = 0; i < length; i += 3) {
waveformBuilder.addRamp(/* amplitude= */ values[i], /* frequency= */ values[i + 1],
/* duration= */ (int) values[i + 2]);
}
if (insistent) {
return waveformBuilder.build(/* repeat= */ 0);
}
return waveformBuilder.build();
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Error creating vibration PWLE waveform with pattern: "
+ Arrays.toString(values));
}
return null;
}
/** /**
* Vibrate the device with given {@code effect}. * Vibrate the device with given {@code effect}.
* *
@@ -106,7 +153,10 @@ public final class VibratorHelper {
*/ */
public VibrationEffect createFallbackVibration(boolean insistent) { public VibrationEffect createFallbackVibration(boolean insistent) {
if (mVibrator.hasFrequencyControl()) { if (mVibrator.hasFrequencyControl()) {
return createChirpVibration(FALLBACK_CHIRP_RAMP_DURATION_MILLIS, insistent); VibrationEffect effect = createPwleWaveformVibration(mFallbackPwlePattern, insistent);
if (effect != null) {
return effect;
}
} }
return createWaveformVibration(mFallbackPattern, insistent); return createWaveformVibration(mFallbackPattern, insistent);
} }
@@ -118,29 +168,29 @@ public final class VibratorHelper {
*/ */
public VibrationEffect createDefaultVibration(boolean insistent) { public VibrationEffect createDefaultVibration(boolean insistent) {
if (mVibrator.hasFrequencyControl()) { if (mVibrator.hasFrequencyControl()) {
return createChirpVibration(DEFAULT_CHIRP_RAMP_DURATION_MILLIS, insistent); VibrationEffect effect = createPwleWaveformVibration(mDefaultPwlePattern, insistent);
if (effect != null) {
return effect;
}
} }
return createWaveformVibration(mDefaultPattern, insistent); return createWaveformVibration(mDefaultPattern, insistent);
} }
private static VibrationEffect createChirpVibration(int rampDuration, boolean insistent) { @Nullable
VibrationEffect.WaveformBuilder waveformBuilder = VibrationEffect.startWaveform() private static float[] getFloatArray(Resources resources, int resId) {
.addStep(/* amplitude= */ 0, /* frequency= */ -0.85f, /* duration= */ 0) TypedArray array = resources.obtainTypedArray(resId);
.addRamp(/* amplitude= */ 1, /* frequency= */ -0.25f, rampDuration) try {
.addStep(/* amplitude= */ 1, /* frequency= */ -0.25f, CHIRP_LEVEL_DURATION_MILLIS) float[] values = new float[array.length()];
.addRamp(/* amplitude= */ 0, /* frequency= */ -0.85f, rampDuration); for (int i = 0; i < values.length; i++) {
values[i] = array.getFloat(i, Float.NaN);
if (insistent) { if (Float.isNaN(values[i])) {
return waveformBuilder return null;
.addStep(/* amplitude= */ 0, CHIRP_LEVEL_DURATION_MILLIS) }
.build(/* repeat= */ 0); }
return values;
} finally {
array.recycle();
} }
VibrationEffect singleBeat = waveformBuilder.build();
return VibrationEffect.startComposition()
.addEffect(singleBeat)
.addEffect(singleBeat, /* delay= */ CHIRP_LEVEL_DURATION_MILLIS)
.compose();
} }
private static long[] getLongArray(Resources resources, int resId, int maxLength, long[] def) { private static long[] getLongArray(Resources resources, int resId, int maxLength, long[] def) {

View File

@@ -40,7 +40,10 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class VibratorHelperTest extends UiServiceTestCase { public class VibratorHelperTest extends UiServiceTestCase {
// OFF/ON vibration pattern
private static final long[] CUSTOM_PATTERN = new long[] { 100, 200, 300, 400 }; private static final long[] CUSTOM_PATTERN = new long[] { 100, 200, 300, 400 };
// (amplitude, frequency, duration) triples list
private static final float[] PWLE_PATTERN = new float[] { 1, 0, 100 };
@Mock private Vibrator mVibrator; @Mock private Vibrator mVibrator;
@@ -58,12 +61,16 @@ public class VibratorHelperTest extends UiServiceTestCase {
public void createWaveformVibration_insistent_createsRepeatingVibration() { public void createWaveformVibration_insistent_createsRepeatingVibration() {
assertRepeatingVibration( assertRepeatingVibration(
VibratorHelper.createWaveformVibration(CUSTOM_PATTERN, /* insistent= */ true)); VibratorHelper.createWaveformVibration(CUSTOM_PATTERN, /* insistent= */ true));
assertRepeatingVibration(
VibratorHelper.createPwleWaveformVibration(PWLE_PATTERN, /* insistent= */ true));
} }
@Test @Test
public void createWaveformVibration_nonInsistent_createsSingleShotVibration() { public void createWaveformVibration_nonInsistent_createsSingleShotVibration() {
assertSingleVibration( assertSingleVibration(
VibratorHelper.createWaveformVibration(CUSTOM_PATTERN, /* insistent= */ false)); VibratorHelper.createWaveformVibration(CUSTOM_PATTERN, /* insistent= */ false));
assertSingleVibration(
VibratorHelper.createPwleWaveformVibration(PWLE_PATTERN, /* insistent= */ false));
} }
@Test @Test
@@ -71,6 +78,11 @@ public class VibratorHelperTest extends UiServiceTestCase {
assertNull(VibratorHelper.createWaveformVibration(null, false)); assertNull(VibratorHelper.createWaveformVibration(null, false));
assertNull(VibratorHelper.createWaveformVibration(new long[0], false)); assertNull(VibratorHelper.createWaveformVibration(new long[0], false));
assertNull(VibratorHelper.createWaveformVibration(new long[] { 0, 0 }, false)); assertNull(VibratorHelper.createWaveformVibration(new long[] { 0, 0 }, false));
assertNull(VibratorHelper.createPwleWaveformVibration(null, false));
assertNull(VibratorHelper.createPwleWaveformVibration(new float[0], false));
assertNull(VibratorHelper.createPwleWaveformVibration(new float[] { 0 }, false));
assertNull(VibratorHelper.createPwleWaveformVibration(new float[] { 0, 0, 0 }, false));
} }
@Test @Test