summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java131
1 files changed, 131 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 804cf4663bfd..9de46c878194 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -2715,6 +2715,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
addPrebakedToComposition(composition);
} else if ("primitives".equals(nextArg)) {
addPrimitivesToComposition(composition);
+ } else if ("envelope".equals(nextArg)) {
+ addEnvelopeToComposition(composition);
} else {
// nextArg is not an effect, finish reading.
break;
@@ -2745,6 +2747,121 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
composition.addEffect(VibrationEffect.createOneShot(duration, amplitude));
}
+ private interface EnvelopeBuilder {
+ void setInitialSharpness(float sharpness);
+ void addControlPoint(float intensity, float sharpness, long duration);
+ void reset(float initialSharpness);
+ VibrationEffect build();
+ }
+
+ private static class BasicEnveloperBuilderWrapper implements EnvelopeBuilder {
+ private VibrationEffect.BasicEnvelopeBuilder mBuilder =
+ new VibrationEffect.BasicEnvelopeBuilder();
+
+ @Override
+ public void setInitialSharpness(float sharpness) {
+ mBuilder.setInitialSharpness(sharpness);
+ }
+
+ @Override
+ public void addControlPoint(float intensity, float sharpness, long duration) {
+ mBuilder.addControlPoint(intensity, sharpness, duration);
+ }
+
+ @Override
+ public void reset(float initialSharpness) {
+ mBuilder = new VibrationEffect.BasicEnvelopeBuilder();
+ mBuilder.setInitialSharpness(initialSharpness);
+ }
+
+ @Override
+ public VibrationEffect build() {
+ return mBuilder.build();
+ }
+ }
+
+ private static class AdvancedEnveloperBuilderWrapper implements EnvelopeBuilder {
+ private VibrationEffect.WaveformEnvelopeBuilder mBuilder =
+ new VibrationEffect.WaveformEnvelopeBuilder();
+
+ @Override
+ public void setInitialSharpness(float sharpness) {
+ mBuilder.setInitialFrequencyHz(sharpness);
+ }
+
+ @Override
+ public void addControlPoint(float intensity, float sharpness, long duration) {
+ mBuilder.addControlPoint(intensity, sharpness, duration);
+ }
+
+ @Override
+ public void reset(float initialSharpness) {
+ mBuilder = new VibrationEffect.WaveformEnvelopeBuilder();
+ mBuilder.setInitialFrequencyHz(initialSharpness);
+ }
+
+ @Override
+ public VibrationEffect build() {
+ return mBuilder.build();
+ }
+ }
+
+ private void addEnvelopeToComposition(VibrationEffect.Composition composition) {
+ getNextArgRequired(); // consume "envelope"
+ int repeat = -1;
+ float initialSharpness = Float.NaN;
+ VibrationEffect preamble = null;
+ boolean isAdvanced = false;
+ String nextOption;
+ while ((nextOption = getNextOption()) != null) {
+ switch (nextOption) {
+ case "-a" -> isAdvanced = true;
+ case "-i" -> initialSharpness = Float.parseFloat(getNextArgRequired());
+ case "-r" -> repeat = Integer.parseInt(getNextArgRequired());
+ }
+ }
+
+ EnvelopeBuilder builder = isAdvanced ? new AdvancedEnveloperBuilderWrapper()
+ : new BasicEnveloperBuilderWrapper();
+
+ if (!Float.isNaN(initialSharpness)) {
+ builder.setInitialSharpness(initialSharpness);
+ }
+
+ int duration, pos = 0;
+ float intensity, sharpness = 0f;
+ String nextArg;
+ while ((nextArg = peekNextArg()) != null) {
+ if (pos > 0 && pos == repeat) {
+ preamble = builder.build();
+ builder.reset(sharpness);
+ }
+ try {
+ duration = Integer.parseInt(nextArg);
+ getNextArgRequired(); // consume the duration
+ } catch (NumberFormatException e) {
+ // nextArg is not a duration, finish reading.
+ break;
+ }
+ intensity = Float.parseFloat(getNextArgRequired());
+ sharpness = Float.parseFloat(getNextArgRequired());
+ builder.addControlPoint(intensity, sharpness, duration);
+ pos++;
+ }
+
+ if (repeat >= 0) {
+ if (preamble == null) {
+ composition.addEffect(VibrationEffect.createRepeatingEffect(builder.build()));
+ } else {
+ composition.addEffect(
+ VibrationEffect.createRepeatingEffect(preamble, builder.build()));
+ }
+ return;
+ }
+
+ composition.addEffect(builder.build());
+ }
+
private void addWaveformToComposition(VibrationEffect.Composition composition) {
boolean hasAmplitudes = false;
boolean hasFrequencies = false;
@@ -2979,6 +3096,20 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
pw.println(" between values; otherwise each entry is a fixed step.");
pw.println(" Duration is in milliseconds; amplitude is a scale of 1-255;");
pw.println(" frequency is an absolute value in hertz;");
+ pw.print(" envelope [-a] [-i initial sharpness] [-r index] ");
+ pw.println("[<duration1> <intensity1> <sharpness1>]...");
+ pw.println(" Generates a vibration pattern based on a series of duration, ");
+ pw.println(" intensity, and sharpness values. The total vibration time is ");
+ pw.println(" the sum of all durations; Ignored when device is on ");
+ pw.println(" DND (Do Not Disturb) mode; touch feedback strength user setting ");
+ pw.println(" will be used to scale amplitude.");
+ pw.println(" If -a is provided, the waveform will use the advanced APIs to ");
+ pw.println(" generate the vibration pattern and the input parameters ");
+ pw.println(" become [<duration1> <amplitude1> <frequency1>].");
+ pw.println(" If -i is provided, the waveform will have an initial sharpness ");
+ pw.println(" it will start from.");
+ pw.println(" If -r is provided, the waveform loops back to the specified index");
+ pw.println(" (e.g. 0 loops from the beginning).");
pw.println(" prebaked [-w delay] [-b] <effect-id>");
pw.println(" Vibrates with prebaked effect; ignored when device is on DND ");
pw.println(" (Do Not Disturb) mode; touch feedback strength user setting ");