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

Commit c25834c5 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Introduce primitive scale to vibrator adb" into main

parents 9a8a9152 6944e462
Loading
Loading
Loading
Loading
+89 −68
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ import android.os.VibratorInfo;
import android.os.vibrator.Flags;
import android.os.vibrator.IVibrationSessionCallback;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
import android.os.vibrator.VibrationConfig;
import android.os.vibrator.VibrationEffectSegment;
import android.os.vibrator.VibratorInfoFactory;
@@ -2672,7 +2673,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
            CombinedVibration.ParallelCombination combination =
                    CombinedVibration.startParallel();
            while ("-v".equals(getNextOption())) {
                int vibratorId = Integer.parseInt(getNextArgRequired());
                int vibratorId = parseInt(getNextArgRequired(), "Expected vibrator id after -v");
                combination.addVibrator(vibratorId, nextEffect());
            }
            runVibrate(commonOptions, combination.combine());
@@ -2684,7 +2685,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
            CombinedVibration.SequentialCombination combination =
                    CombinedVibration.startSequential();
            while ("-v".equals(getNextOption())) {
                int vibratorId = Integer.parseInt(getNextArgRequired());
                int vibratorId = parseInt(getNextArgRequired(), "Expected vibrator id after -v");
                combination.addNext(vibratorId, nextEffect());
            }
            runVibrate(commonOptions, combination.combine());
@@ -2709,7 +2710,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {

        private int runHapticFeedback() {
            CommonOptions commonOptions = new CommonOptions();
            int constant = Integer.parseInt(getNextArgRequired());
            int constant = parseInt(getNextArgRequired(), "Expected haptic feedback constant id");

            IBinder deathBinder = commonOptions.background ? VibratorManagerService.this
                    : mShellCallbacksToken;
@@ -2757,12 +2758,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                if ("-a".equals(nextOption)) {
                    hasAmplitude = true;
                } else if ("-w".equals(nextOption)) {
                    delay = Integer.parseInt(getNextArgRequired());
                    delay = parseInt(getNextArgRequired(), "Expected delay millis after -w");
                }
            }

            long duration = Long.parseLong(getNextArgRequired());
            int amplitude = hasAmplitude ? Integer.parseInt(getNextArgRequired())
            long duration = parseInt(getNextArgRequired(), "Expected one-shot duration millis");
            int amplitude = hasAmplitude
                    ? parseInt(getNextArgRequired(), "Expected one-shot amplitude")
                    : VibrationEffect.DEFAULT_AMPLITUDE;
            composition.addOffDuration(Duration.ofMillis(delay));
            composition.addEffect(VibrationEffect.createOneShot(duration, amplitude));
@@ -2837,8 +2839,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
            while ((nextOption = getNextOption()) != null) {
                switch (nextOption) {
                    case "-a" -> isAdvanced = true;
                    case "-i" -> initialSharpness = Float.parseFloat(getNextArgRequired());
                    case "-r" -> repeat = Integer.parseInt(getNextArgRequired());
                    case "-i" -> initialSharpness = parseFloat(getNextArgRequired(),
                            "Expected initial sharpness after -i");
                    case "-r" -> repeat = parseInt(getNextArgRequired(),
                            "Expected repeat index after -r");
                }
            }

@@ -2864,8 +2868,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                    // nextArg is not a duration, finish reading.
                    break;
                }
                intensity = Float.parseFloat(getNextArgRequired());
                sharpness = Float.parseFloat(getNextArgRequired());
                intensity = parseFloat(getNextArgRequired(), "Expected envelope intensity");
                sharpness = parseFloat(getNextArgRequired(), "Expected envelope sharpness");
                builder.addControlPoint(intensity, sharpness, duration);
                pos++;
            }
@@ -2893,16 +2897,14 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
            getNextArgRequired(); // consume "waveform"
            String nextOption;
            while ((nextOption = getNextOption()) != null) {
                if ("-a".equals(nextOption)) {
                    hasAmplitudes = true;
                } else if ("-r".equals(nextOption)) {
                    repeat = Integer.parseInt(getNextArgRequired());
                } else if ("-w".equals(nextOption)) {
                    delay = Integer.parseInt(getNextArgRequired());
                } else if ("-f".equals(nextOption)) {
                    hasFrequencies = true;
                } else if ("-c".equals(nextOption)) {
                    isContinuous = true;
                switch (nextOption) {
                    case "-a" -> hasAmplitudes = true;
                    case "-f" -> hasFrequencies = true;
                    case "-c" -> isContinuous = true;
                    case "-r" -> repeat = parseInt(getNextArgRequired(),
                            "Expected repeat index after -r");
                    case "-w" -> delay = parseInt(getNextArgRequired(),
                            "Expected delay millis after -w");
                }
            }
            List<Integer> durations = new ArrayList<>();
@@ -2920,14 +2922,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                    break;
                }
                if (hasAmplitudes) {
                    amplitudes.add(
                            Float.parseFloat(getNextArgRequired()) / VibrationEffect.MAX_AMPLITUDE);
                    int amplitude = parseInt(getNextArgRequired(), "Expected waveform amplitude");
                    amplitudes.add((float) amplitude / VibrationEffect.MAX_AMPLITUDE);
                } else {
                    amplitudes.add(nextAmplitude);
                    nextAmplitude = 1 - nextAmplitude;
                }
                if (hasFrequencies) {
                    frequencies.add(Float.parseFloat(getNextArgRequired()));
                    frequencies.add(
                            parseFloat(getNextArgRequired(), "Expected waveform frequency"));
                }
            }

@@ -2986,27 +2989,37 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                if ("-b".equals(nextOption)) {
                    shouldFallback = true;
                } else if ("-w".equals(nextOption)) {
                    delay = Integer.parseInt(getNextArgRequired());
                    delay = parseInt(getNextArgRequired(), "Expected delay millis after -w");
                }
            }

            int effectId = Integer.parseInt(getNextArgRequired());
            int effectId = parseInt(getNextArgRequired(), "Expected prebaked effect id");
            composition.addOffDuration(Duration.ofMillis(delay));
            composition.addEffect(VibrationEffect.get(effectId, shouldFallback));
        }

        private void addPrimitivesToComposition(VibrationEffect.Composition composition) {
            getNextArgRequired(); // consume "primitives"
            String nextArg;
            while ((nextArg = peekNextArg()) != null) {
            while (peekNextArg() != null) {
                int delay = 0;
                if ("-w".equals(nextArg)) {
                    getNextArgRequired(); // consume "-w"
                    delay = Integer.parseInt(getNextArgRequired());
                    nextArg = peekNextArg();
                float scale = 1f;
                int delayType = PrimitiveSegment.DEFAULT_DELAY_TYPE;

                String nextOption;
                while ((nextOption = getNextOption()) != null) {
                    if ("-s".equals(nextOption)) {
                        scale = parseFloat(getNextArgRequired(), "Expected scale after -s");
                    } else if ("-o".equals(nextOption)) {
                        delayType = VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET;
                        delay = parseInt(getNextArgRequired(), "Expected offset millis after -o");
                    } else if ("-w".equals(nextOption)) {
                        delayType = PrimitiveSegment.DEFAULT_DELAY_TYPE;
                        delay = parseInt(getNextArgRequired(), "Expected delay millis after -w");
                    }
                }
                try {
                    composition.addPrimitive(Integer.parseInt(nextArg), /* scale= */ 1, delay);
                    String nextArg = peekNextArg(); // Just in case this is not a primitive.
                    composition.addPrimitive(Integer.parseInt(nextArg), scale, delay, delayType);
                    getNextArgRequired(); // consume the primitive id
                } catch (NumberFormatException | NullPointerException e) {
                    // nextArg is not describing a primitive, leave it to be consumed by outer loops
@@ -3032,17 +3045,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                        VibrationXmlParser.parseDocument(new StringReader(xml));
                VibratorInfo combinedVibratorInfo = getCombinedVibratorInfo();
                if (combinedVibratorInfo == null) {
                    throw new IllegalStateException(
                            "No combined vibrator info to parse vibration XML " + xml);
                    throw new IllegalStateException("No vibrator info available to parse XML");
                }
                VibrationEffect effect = parsedVibration.resolve(combinedVibratorInfo);
                if (effect == null) {
                    throw new IllegalArgumentException(
                            "Parsed vibration cannot be resolved for vibration XML " + xml);
                    throw new IllegalArgumentException("Parsed XML cannot be resolved: " + xml);
                }
                return CombinedVibration.createParallel(effect);
            } catch (IOException e) {
                throw new RuntimeException("Error parsing vibration XML " + xml, e);
                throw new RuntimeException("Error parsing XML: " + xml, e);
            }
        }

@@ -3060,16 +3071,30 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
            }
        }

        private static int parseInt(String text, String errorMessage) {
            try {
                return Integer.parseInt(text);
            } catch (NumberFormatException | NullPointerException e) {
                throw new IllegalArgumentException(errorMessage, e);
            }
        }

        private static float parseFloat(String text, String errorMessage) {
            try {
                return Float.parseFloat(text);
            } catch (NumberFormatException | NullPointerException e) {
                throw new IllegalArgumentException(errorMessage, e);
            }
        }

        @Override
        public void onHelp() {
            try (PrintWriter pw = getOutPrintWriter();) {
                pw.println("Vibrator Manager commands:");
                pw.println("  help");
                pw.println("    Prints this help text.");
                pw.println("");
                pw.println("  list");
                pw.println("    Prints the id of device vibrators. This does not include any ");
                pw.println("    connected input device.");
                pw.println("    Prints device vibrator ids; does not include input devices.");
                pw.println("  synced [options] <effect>...");
                pw.println("    Vibrates effect on all vibrators in sync.");
                pw.println("  combined [options] (-v <vibrator-id> <effect>...)...");
@@ -3079,51 +3104,41 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                pw.println("  xml [options] <xml>");
                pw.println("    Vibrates using combined vibration described in given XML string");
                pw.println("    on all vibrators in sync. The XML could be:");
                pw.println("        XML containing a single effect, or");
                pw.println("        A vibration select XML containing multiple effects.");
                pw.println("    Vibrates using combined vibration described in given XML string.");
                pw.println("    XML containing a single effect it runs on all vibrators in sync.");
                pw.println("        A single <vibration-effect>, or");
                pw.println("        A <vibration-select> containing multiple effects.");
                pw.println("  feedback [options] <constant>");
                pw.println("    Performs a haptic feedback with the given constant.");
                pw.println("  cancel");
                pw.println("    Cancels any active vibration");
                pw.println("  feedback [-f] [-d <description>] <constant>");
                pw.println("    Performs a haptic feedback with the given constant.");
                pw.println("    The force (-f) option enables the `always` configuration, which");
                pw.println("    plays the haptic irrespective of the vibration intensity settings");
                pw.println("");
                pw.println("Effect commands:");
                pw.println("  oneshot [-w delay] [-a] <duration> [<amplitude>]");
                pw.println("    Vibrates for duration milliseconds; 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("    Vibrates for duration milliseconds.");
                pw.println("    If -w is provided, the effect will be played after the specified");
                pw.println("    wait time in milliseconds.");
                pw.println("    If -a is provided, the command accepts a second argument for ");
                pw.println("    amplitude, in a scale of 1-255.");
                pw.print("  waveform [-w delay] [-r index] [-a] [-f] [-c] ");
                pw.println("(<duration> [<amplitude>] [<frequency>])...");
                pw.println("    Vibrates for durations and amplitudes in list; ignored when ");
                pw.println("    device is on DND (Do Not Disturb) mode; touch feedback strength ");
                pw.println("    user setting will be used to scale amplitude.");
                pw.println("    Vibrates for durations and amplitudes in list.");
                pw.println("    If -w is provided, the effect will be played after the specified");
                pw.println("    wait time in milliseconds.");
                pw.println("    If -r is provided, the waveform loops back to the specified");
                pw.println("    index (e.g. 0 loops from the beginning)");
                pw.println("    index (e.g. 0 loops from the beginning).");
                pw.println("    If -a is provided, the command expects amplitude to follow each");
                pw.println("    duration; otherwise, it accepts durations only and alternates");
                pw.println("    off/on");
                pw.println("    off/on.");
                pw.println("    If -f is provided, the command expects frequency to follow each");
                pw.println("    amplitude or duration; otherwise, it uses resonant frequency");
                pw.println("    amplitude or duration; otherwise, it uses resonant frequency.");
                pw.println("    If -c is provided, the waveform is continuous and will ramp");
                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.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("    the sum of all durations.");
                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>].");
@@ -3132,19 +3147,20 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                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 ");
                pw.println("    will be used to scale amplitude.");
                pw.println("    Vibrates with prebaked effect.");
                pw.println("    If -w is provided, the effect will be played after the specified");
                pw.println("    wait time in milliseconds.");
                pw.println("    If -b is provided, the prebaked fallback effect will be played if");
                pw.println("    the device doesn't support the given effect-id.");
                pw.println("  primitives ([-w delay] <primitive-id>)...");
                pw.println("    Vibrates with a composed effect; ignored when device is on DND ");
                pw.println("    (Do Not Disturb) mode; touch feedback strength user setting ");
                pw.println("    will be used to scale primitive intensities.");
                pw.print("  primitives ([-w delay] [-o time] [-s scale]");
                pw.println("<primitive-id> [<scale>])...");
                pw.println("    Vibrates with a composed effect.");
                pw.println("    If -w is provided, the next primitive will be played after the ");
                pw.println("    specified wait time in milliseconds.");
                pw.println("    If -o is provided, the next primitive will be played at the ");
                pw.println("    specified start offset time in milliseconds.");
                pw.println("    If -s is provided, the next primitive will be played with the");
                pw.println("    specified amplitude scale, in a scale of [0,1].");
                pw.println("");
                pw.println("Common Options:");
                pw.println("  -f");
@@ -3155,6 +3171,11 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                pw.println("  -d <description>");
                pw.println("    Add description to the vibration.");
                pw.println("");
                pw.println("Notes");
                pw.println("    Vibrations triggered by these commands will be ignored when");
                pw.println("    device is on DND (Do Not Disturb) mode; notification strength");
                pw.println("    user settings will be applied for scale.");
                pw.println("");
            }
        }
    }