summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLais Andrade <lsandrade@google.com>2022-01-13 13:52:55 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2022-01-13 13:52:55 +0000
commit68fe893dd5cf56085b53e62270a90cfa1b4cc1f0 (patch)
treee202e82b52bba7a0e77c474ff9029ec2011f9371
parent44cd0e46644b792cc7a1340b3bcfc86acd5a8502 (diff)
parent3680feb9036378ef1d638f6b248d02401b25b962 (diff)
downloadbase-68fe893dd5cf56085b53e62270a90cfa1b4cc1f0.tar.gz
Merge "Move PWLE notification vibration pattern to config.xml" into sc-v2-dev
-rw-r--r--core/res/res/values/config.xml20
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--services/core/java/com/android/server/notification/VibratorHelper.java98
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java12
4 files changed, 108 insertions, 24 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7bedcc67dc6d..4334476b82a6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2679,6 +2679,16 @@
<item>350</item>
</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
that do not specify vibration but vibrate anyway because the device
is in vibrate mode.
@@ -2690,6 +2700,16 @@
<item>100</item>
</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 -->
<bool name="config_speed_up_audio_on_mt_calls">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 46b249e5be6d..1a215b6696a9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1917,7 +1917,9 @@
<java-symbol type="array" name="config_locationExtraPackageNames" />
<java-symbol type="array" name="config_testLocationProviders" />
<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_notificationFallbackVibeWaveform" />
<java-symbol type="bool" name="config_enableServerNotificationEffectsForAutomotive" />
<java-symbol type="bool" name="config_useAttentionLight" />
<java-symbol type="bool" name="config_adaptive_sleep_available" />
diff --git a/services/core/java/com/android/server/notification/VibratorHelper.java b/services/core/java/com/android/server/notification/VibratorHelper.java
index 0a69aec76306..449fae13f137 100644
--- a/services/core/java/com/android/server/notification/VibratorHelper.java
+++ b/services/core/java/com/android/server/notification/VibratorHelper.java
@@ -19,6 +19,7 @@ package com.android.server.notification;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.media.AudioAttributes;
import android.os.Process;
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 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 long[] mDefaultPattern;
private final long[] mFallbackPattern;
+ @Nullable private final float[] mDefaultPwlePattern;
+ @Nullable private final float[] mFallbackPwlePattern;
public VibratorHelper(Context context) {
mVibrator = context.getSystemService(Vibrator.class);
- mDefaultPattern = getLongArray(
- context.getResources(),
+ mDefaultPattern = getLongArray(context.getResources(),
com.android.internal.R.array.config_defaultNotificationVibePattern,
VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN);
@@ -58,6 +57,10 @@ public final class VibratorHelper {
R.array.config_notificationFallbackVibePattern,
VIBRATE_PATTERN_MAXLEN,
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);
}
/**
@@ -83,6 +86,50 @@ public final class VibratorHelper {
}
/**
+ * 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}.
*
* <p>We need to vibrate as "android" so we can breakthrough DND.
@@ -106,7 +153,10 @@ public final class VibratorHelper {
*/
public VibrationEffect createFallbackVibration(boolean insistent) {
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);
}
@@ -118,29 +168,29 @@ public final class VibratorHelper {
*/
public VibrationEffect createDefaultVibration(boolean insistent) {
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);
}
- private static VibrationEffect createChirpVibration(int rampDuration, boolean insistent) {
- VibrationEffect.WaveformBuilder waveformBuilder = VibrationEffect.startWaveform()
- .addStep(/* amplitude= */ 0, /* frequency= */ -0.85f, /* duration= */ 0)
- .addRamp(/* amplitude= */ 1, /* frequency= */ -0.25f, rampDuration)
- .addStep(/* amplitude= */ 1, /* frequency= */ -0.25f, CHIRP_LEVEL_DURATION_MILLIS)
- .addRamp(/* amplitude= */ 0, /* frequency= */ -0.85f, rampDuration);
-
- if (insistent) {
- return waveformBuilder
- .addStep(/* amplitude= */ 0, CHIRP_LEVEL_DURATION_MILLIS)
- .build(/* repeat= */ 0);
+ @Nullable
+ private static float[] getFloatArray(Resources resources, int resId) {
+ TypedArray array = resources.obtainTypedArray(resId);
+ try {
+ float[] values = new float[array.length()];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = array.getFloat(i, Float.NaN);
+ if (Float.isNaN(values[i])) {
+ return null;
+ }
+ }
+ 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) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java
index c77a474e032c..8bc0c6c65fa3 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java
@@ -40,7 +40,10 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class VibratorHelperTest extends UiServiceTestCase {
+ // OFF/ON vibration pattern
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;
@@ -58,12 +61,16 @@ public class VibratorHelperTest extends UiServiceTestCase {
public void createWaveformVibration_insistent_createsRepeatingVibration() {
assertRepeatingVibration(
VibratorHelper.createWaveformVibration(CUSTOM_PATTERN, /* insistent= */ true));
+ assertRepeatingVibration(
+ VibratorHelper.createPwleWaveformVibration(PWLE_PATTERN, /* insistent= */ true));
}
@Test
public void createWaveformVibration_nonInsistent_createsSingleShotVibration() {
assertSingleVibration(
VibratorHelper.createWaveformVibration(CUSTOM_PATTERN, /* insistent= */ false));
+ assertSingleVibration(
+ VibratorHelper.createPwleWaveformVibration(PWLE_PATTERN, /* insistent= */ false));
}
@Test
@@ -71,6 +78,11 @@ public class VibratorHelperTest extends UiServiceTestCase {
assertNull(VibratorHelper.createWaveformVibration(null, false));
assertNull(VibratorHelper.createWaveformVibration(new long[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