diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 0461b2eb413b6..c3d7540b8cb2f 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -232,11 +232,11 @@ public abstract class VibrationEffect implements Parcelable {
* Computes a legacy vibration pattern (i.e. a pattern with duration values for "off/on"
* vibration components) that is equivalent to this VibrationEffect.
*
- *
All non-repeating effects created with {@link #createWaveform(int[], int)} are convertible
- * into an equivalent vibration pattern with this method. It is not guaranteed that an effect
- * created with other means becomes converted into an equivalent legacy vibration pattern, even
- * if it has an equivalent vibration pattern. If this method is unable to create an equivalent
- * vibration pattern for such effects, it will return {@code null}.
+ *
All non-repeating effects created with {@link #createWaveform(long[], int)} are
+ * convertible into an equivalent vibration pattern with this method. It is not guaranteed that
+ * an effect created with other means becomes converted into an equivalent legacy vibration
+ * pattern, even if it has an equivalent vibration pattern. If this method is unable to create
+ * an equivalent vibration pattern for such effects, it will return {@code null}.
*
*
Note that a valid equivalent long[] pattern cannot be created for an effect that has any
* form of repeating behavior, regardless of how the effect was created. For repeating effects,
@@ -245,7 +245,7 @@ public abstract class VibrationEffect implements Parcelable {
* @return a long array representing a vibration pattern equivalent to the VibrationEffect, if
* the method successfully derived a vibration pattern equivalent to the effect
* (this will always be the case if the effect was created via
- * {@link #createWaveform(int[], int)} and is non-repeating). Otherwise, returns
+ * {@link #createWaveform(long[], int)} and is non-repeating). Otherwise, returns
* {@code null}.
* @hide
*/
@@ -953,7 +953,7 @@ public abstract class VibrationEffect implements Parcelable {
/**
* Casts a provided {@link VibrationEffectSegment} to a {@link StepSegment} and returns it,
* only if it can possibly be a segment for an effect created via
- * {@link #createWaveform(int[], int)}. Otherwise, returns {@code null}.
+ * {@link #createWaveform(long[], int)}. Otherwise, returns {@code null}.
*/
@Nullable
private static StepSegment castToValidStepSegmentForOffOnTimingsOrNull(
diff --git a/core/java/android/os/vibrator/PrebakedSegment.java b/core/java/android/os/vibrator/PrebakedSegment.java
index da2ee6c756098..462e5add9d33e 100644
--- a/core/java/android/os/vibrator/PrebakedSegment.java
+++ b/core/java/android/os/vibrator/PrebakedSegment.java
@@ -118,12 +118,6 @@ public final class PrebakedSegment extends VibrationEffectSegment {
}
}
- /** @hide */
- @Override
- public boolean hasNonZeroAmplitude() {
- return true;
- }
-
/** @hide */
@NonNull
@Override
diff --git a/core/java/android/os/vibrator/PrimitiveSegment.java b/core/java/android/os/vibrator/PrimitiveSegment.java
index e1fa97b34bd1f..815a1dc363e3c 100644
--- a/core/java/android/os/vibrator/PrimitiveSegment.java
+++ b/core/java/android/os/vibrator/PrimitiveSegment.java
@@ -87,13 +87,6 @@ public final class PrimitiveSegment extends VibrationEffectSegment {
return true;
}
- /** @hide */
- @Override
- public boolean hasNonZeroAmplitude() {
- // Every primitive plays a vibration with a non-zero amplitude, even at scale == 0.
- return true;
- }
-
/** @hide */
@NonNull
@Override
diff --git a/core/java/android/os/vibrator/RampSegment.java b/core/java/android/os/vibrator/RampSegment.java
index 034962a5f91b1..a5dee6c8e5bcd 100644
--- a/core/java/android/os/vibrator/RampSegment.java
+++ b/core/java/android/os/vibrator/RampSegment.java
@@ -123,12 +123,6 @@ public final class RampSegment extends VibrationEffectSegment {
return true;
}
- /** @hide */
- @Override
- public boolean hasNonZeroAmplitude() {
- return mStartAmplitude > 0 || mEndAmplitude > 0;
- }
-
/** @hide */
@Override
public void validate() {
diff --git a/core/java/android/os/vibrator/StepSegment.java b/core/java/android/os/vibrator/StepSegment.java
index 817187e1cebb8..54a44a88b7521 100644
--- a/core/java/android/os/vibrator/StepSegment.java
+++ b/core/java/android/os/vibrator/StepSegment.java
@@ -99,13 +99,6 @@ public final class StepSegment extends VibrationEffectSegment {
return true;
}
- /** @hide */
- @Override
- public boolean hasNonZeroAmplitude() {
- // DEFAULT_AMPLITUDE == -1 is still a non-zero amplitude that will be resolved later.
- return Float.compare(mAmplitude, 0) != 0;
- }
-
/** @hide */
@Override
public void validate() {
diff --git a/core/java/android/os/vibrator/VibrationEffectSegment.java b/core/java/android/os/vibrator/VibrationEffectSegment.java
index 75a055fa5273b..9a19ed417f497 100644
--- a/core/java/android/os/vibrator/VibrationEffectSegment.java
+++ b/core/java/android/os/vibrator/VibrationEffectSegment.java
@@ -75,13 +75,6 @@ public abstract class VibrationEffectSegment implements Parcelable {
*/
public abstract boolean isHapticFeedbackCandidate();
- /**
- * Returns true if this segment plays at a non-zero amplitude at some point.
- *
- * @hide
- */
- public abstract boolean hasNonZeroAmplitude();
-
/**
* Validates the segment, throwing exceptions if any parameter is invalid.
*
diff --git a/core/tests/vibrator/src/android/os/vibrator/PrebakedSegmentTest.java b/core/tests/vibrator/src/android/os/vibrator/PrebakedSegmentTest.java
index 32311923e3d10..8268077e72e9d 100644
--- a/core/tests/vibrator/src/android/os/vibrator/PrebakedSegmentTest.java
+++ b/core/tests/vibrator/src/android/os/vibrator/PrebakedSegmentTest.java
@@ -45,7 +45,6 @@ public class PrebakedSegmentTest {
VibrationEffect.EFFECT_CLICK, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM);
assertEquals(-1, prebaked.getDuration());
- assertTrue(prebaked.hasNonZeroAmplitude());
assertEquals(VibrationEffect.EFFECT_CLICK, prebaked.getEffectId());
assertEquals(VibrationEffect.EFFECT_STRENGTH_MEDIUM, prebaked.getEffectStrength());
assertTrue(prebaked.shouldFallback());
diff --git a/core/tests/vibrator/src/android/os/vibrator/PrimitiveSegmentTest.java b/core/tests/vibrator/src/android/os/vibrator/PrimitiveSegmentTest.java
index 955d6acb88826..6f5adcd26ba5d 100644
--- a/core/tests/vibrator/src/android/os/vibrator/PrimitiveSegmentTest.java
+++ b/core/tests/vibrator/src/android/os/vibrator/PrimitiveSegmentTest.java
@@ -46,7 +46,6 @@ public class PrimitiveSegmentTest {
VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 10);
assertEquals(-1, primitive.getDuration());
- assertTrue(primitive.hasNonZeroAmplitude());
assertEquals(VibrationEffect.Composition.PRIMITIVE_CLICK, primitive.getPrimitiveId());
assertEquals(10, primitive.getDelay());
assertEquals(1f, primitive.getScale(), TOLERANCE);
diff --git a/core/tests/vibrator/src/android/os/vibrator/RampSegmentTest.java b/core/tests/vibrator/src/android/os/vibrator/RampSegmentTest.java
index dcbb56e22c77d..68870e5a29797 100644
--- a/core/tests/vibrator/src/android/os/vibrator/RampSegmentTest.java
+++ b/core/tests/vibrator/src/android/os/vibrator/RampSegmentTest.java
@@ -54,7 +54,6 @@ public class RampSegmentTest {
/* startFrequencyHz= */ 100, /* endFrequencyHz= */ 200, /* duration= */ 100);
assertEquals(100L, ramp.getDuration());
- assertTrue(ramp.hasNonZeroAmplitude());
assertEquals(1f, ramp.getStartAmplitude());
assertEquals(0f, ramp.getEndAmplitude());
assertEquals(100f, ramp.getStartFrequencyHz());
@@ -95,13 +94,6 @@ public class RampSegmentTest {
() -> new RampSegment(0, 0, /* startFrequencyHz= */ Float.NaN, 0, 0).validate());
}
- @Test
- public void testHasNonZeroAmplitude() {
- assertTrue(new RampSegment(0, 1, 0, 0, 0).hasNonZeroAmplitude());
- assertTrue(new RampSegment(0.01f, 0, 0, 0, 0).hasNonZeroAmplitude());
- assertFalse(new RampSegment(0, 0, 0, 0, 0).hasNonZeroAmplitude());
- }
-
@Test
public void testResolve() {
RampSegment ramp = new RampSegment(0, 1, 0, 0, 0);
diff --git a/core/tests/vibrator/src/android/os/vibrator/StepSegmentTest.java b/core/tests/vibrator/src/android/os/vibrator/StepSegmentTest.java
index f9f1c08ba60d0..34bb892b07d38 100644
--- a/core/tests/vibrator/src/android/os/vibrator/StepSegmentTest.java
+++ b/core/tests/vibrator/src/android/os/vibrator/StepSegmentTest.java
@@ -52,7 +52,6 @@ public class StepSegmentTest {
/* duration= */ 100);
assertEquals(100, step.getDuration());
- assertTrue(step.hasNonZeroAmplitude());
assertEquals(1f, step.getAmplitude());
assertEquals(1f, step.getFrequencyHz());
}
@@ -86,14 +85,6 @@ public class StepSegmentTest {
() -> new StepSegment(1, /* frequencyHz*/ Float.NaN, 10).validate());
}
- @Test
- public void testHasNonZeroAmplitude() {
- assertTrue(new StepSegment(1f, 0, 0).hasNonZeroAmplitude());
- assertTrue(new StepSegment(0.01f, 0, 0).hasNonZeroAmplitude());
- assertTrue(new StepSegment(VibrationEffect.DEFAULT_AMPLITUDE, 0, 0).hasNonZeroAmplitude());
- assertFalse(new StepSegment(0, 0, 0).hasNonZeroAmplitude());
- }
-
@Test
public void testResolve() {
StepSegment original = new StepSegment(VibrationEffect.DEFAULT_AMPLITUDE, 0, 0);
diff --git a/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java b/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java
index 48d477c86220f..111e075a73747 100644
--- a/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java
+++ b/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java
@@ -30,7 +30,7 @@ import java.util.List;
* each frequency.
*
*
The {@link VibratorInfo.FrequencyProfile} is only applicable to PWLE compositions. This
- * adapter is only applied to {@link RampSegment} and leaves all other segments unchanged.
+ * adapter is only applied to {@link RampSegment} and all other segments will remain unchanged.
*/
final class ClippingAmplitudeAndFrequencyAdapter implements VibrationSegmentsAdapter {
@@ -41,13 +41,13 @@ final class ClippingAmplitudeAndFrequencyAdapter implements VibrationSegmentsAda
for (int i = 0; i < segmentCount; i++) {
VibrationEffectSegment segment = segments.get(i);
if (segment instanceof RampSegment) {
- segments.set(i, apply((RampSegment) segment, info));
+ segments.set(i, adaptToVibrator(info, (RampSegment) segment));
}
}
return repeatIndex;
}
- private RampSegment apply(RampSegment segment, VibratorInfo info) {
+ private RampSegment adaptToVibrator(VibratorInfo info, RampSegment segment) {
float clampedStartFrequency = clampFrequency(info, segment.getStartFrequencyHz());
float clampedEndFrequency = clampFrequency(info, segment.getEndFrequencyHz());
return new RampSegment(
diff --git a/services/core/java/com/android/server/vibrator/DeviceAdapter.java b/services/core/java/com/android/server/vibrator/DeviceAdapter.java
index 41649fac54f01..98309cd007580 100644
--- a/services/core/java/com/android/server/vibrator/DeviceAdapter.java
+++ b/services/core/java/com/android/server/vibrator/DeviceAdapter.java
@@ -53,9 +53,14 @@ final class DeviceAdapter implements CombinedVibration.VibratorAdapter {
mSegmentAdapters = Arrays.asList(
// TODO(b/167947076): add filter that removes unsupported primitives
// TODO(b/167947076): add filter that replaces unsupported prebaked with fallback
+ // Convert segments based on device capabilities
new RampToStepAdapter(settings.getRampStepDuration()),
new StepToRampAdapter(),
+ // Add extra ramp down segments as needed
new RampDownAdapter(settings.getRampDownDuration(), settings.getRampStepDuration()),
+ // Split segments based on their duration and device supported limits
+ new SplitSegmentsAdapter(),
+ // Clip amplitudes and frequencies of final segments based on device bandwidth curve
new ClippingAmplitudeAndFrequencyAdapter()
);
mAvailableVibrators = vibrators;
diff --git a/services/core/java/com/android/server/vibrator/RampToStepAdapter.java b/services/core/java/com/android/server/vibrator/RampToStepAdapter.java
index 9e248cd5effcf..fc19e27ed92c8 100644
--- a/services/core/java/com/android/server/vibrator/RampToStepAdapter.java
+++ b/services/core/java/com/android/server/vibrator/RampToStepAdapter.java
@@ -28,9 +28,11 @@ import java.util.Arrays;
import java.util.List;
/**
- * Adapter that converts ramp segments that to a sequence of fixed step segments.
+ * Adapter that converts ramp segments to a sequence of fixed step segments.
*
- *
This leaves the list unchanged if the device has compose PWLE capability.
+ *
This change preserves the frequency parameters by interpolating the ramp values.
+ *
+ *
The segments will not be changed if the device has {@link IVibrator#CAP_COMPOSE_PWLE_EFFECTS}.
*/
final class RampToStepAdapter implements VibrationSegmentsAdapter {
@@ -53,7 +55,7 @@ final class RampToStepAdapter implements VibrationSegmentsAdapter {
if (!(segment instanceof RampSegment)) {
continue;
}
- List steps = apply(info, (RampSegment) segment);
+ List steps = convertRampToSteps(info, (RampSegment) segment);
segments.remove(i);
segments.addAll(i, steps);
int addedSegments = steps.size() - 1;
@@ -66,7 +68,7 @@ final class RampToStepAdapter implements VibrationSegmentsAdapter {
return repeatIndex;
}
- private List apply(VibratorInfo info, RampSegment ramp) {
+ private List convertRampToSteps(VibratorInfo info, RampSegment ramp) {
if (Float.compare(ramp.getStartAmplitude(), ramp.getEndAmplitude()) == 0) {
// Amplitude is the same, so return a single step to simulate this ramp.
return Arrays.asList(
diff --git a/services/core/java/com/android/server/vibrator/SplitSegmentsAdapter.java b/services/core/java/com/android/server/vibrator/SplitSegmentsAdapter.java
new file mode 100644
index 0000000000000..347db35442148
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/SplitSegmentsAdapter.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.hardware.vibrator.IVibrator;
+import android.os.VibratorInfo;
+import android.os.vibrator.RampSegment;
+import android.os.vibrator.VibrationEffectSegment;
+import android.util.MathUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Adapter that splits segments with longer duration than the device capabilities.
+ *
+ * This transformation replaces large {@link RampSegment} entries by a sequence of smaller
+ * ramp segments that starts and ends at the same amplitudes/frequencies, interpolating the
+ * intermediate values.
+ *
+ *
The segments will not be changed if the device doesn't have
+ * {@link IVibrator#CAP_COMPOSE_PWLE_EFFECTS}.
+ */
+final class SplitSegmentsAdapter implements VibrationSegmentsAdapter {
+
+ @Override
+ public int adaptToVibrator(VibratorInfo info, List segments,
+ int repeatIndex) {
+ if (!info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
+ // The vibrator does not have PWLE capability, so keep the segments unchanged.
+ return repeatIndex;
+ }
+ int maxRampDuration = info.getPwlePrimitiveDurationMax();
+ if (maxRampDuration <= 0) {
+ // No limit set to PWLE primitive duration.
+ return repeatIndex;
+ }
+
+ int segmentCount = segments.size();
+ for (int i = 0; i < segmentCount; i++) {
+ if (!(segments.get(i) instanceof RampSegment)) {
+ continue;
+ }
+ RampSegment ramp = (RampSegment) segments.get(i);
+ int splits = ((int) ramp.getDuration() + maxRampDuration - 1) / maxRampDuration;
+ if (splits <= 1) {
+ continue;
+ }
+ segments.remove(i);
+ segments.addAll(i, splitRampSegment(info, ramp, splits));
+ int addedSegments = splits - 1;
+ if (repeatIndex > i) {
+ repeatIndex += addedSegments;
+ }
+ i += addedSegments;
+ segmentCount += addedSegments;
+ }
+
+ return repeatIndex;
+ }
+
+ private static List splitRampSegment(VibratorInfo info, RampSegment ramp,
+ int splits) {
+ List ramps = new ArrayList<>(splits);
+ // Fill zero frequency values with the device resonant frequency before interpolating.
+ float startFrequencyHz = fillEmptyFrequency(info, ramp.getStartFrequencyHz());
+ float endFrequencyHz = fillEmptyFrequency(info, ramp.getEndFrequencyHz());
+ long splitDuration = ramp.getDuration() / splits;
+ float previousAmplitude = ramp.getStartAmplitude();
+ float previousFrequencyHz = startFrequencyHz;
+ long accumulatedDuration = 0;
+
+ for (int i = 1; i < splits; i++) {
+ accumulatedDuration += splitDuration;
+ float durationRatio = (float) accumulatedDuration / ramp.getDuration();
+ float interpolatedFrequency =
+ MathUtils.lerp(startFrequencyHz, endFrequencyHz, durationRatio);
+ float interpolatedAmplitude =
+ MathUtils.lerp(ramp.getStartAmplitude(), ramp.getEndAmplitude(), durationRatio);
+ RampSegment rampSplit = new RampSegment(
+ previousAmplitude, interpolatedAmplitude,
+ previousFrequencyHz, interpolatedFrequency,
+ (int) splitDuration);
+ ramps.add(rampSplit);
+ previousAmplitude = rampSplit.getEndAmplitude();
+ previousFrequencyHz = rampSplit.getEndFrequencyHz();
+ }
+
+ ramps.add(new RampSegment(previousAmplitude, ramp.getEndAmplitude(), previousFrequencyHz,
+ endFrequencyHz, (int) (ramp.getDuration() - accumulatedDuration)));
+
+ return ramps;
+ }
+
+ private static float fillEmptyFrequency(VibratorInfo info, float frequencyHz) {
+ if (Float.isNaN(info.getResonantFrequencyHz())) {
+ return frequencyHz;
+ }
+ return frequencyHz == 0 ? info.getResonantFrequencyHz() : frequencyHz;
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/StepToRampAdapter.java b/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
index d86ee7858c572..6616f10cf304c 100644
--- a/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
+++ b/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
@@ -21,17 +21,17 @@ import android.os.VibratorInfo;
import android.os.vibrator.RampSegment;
import android.os.vibrator.StepSegment;
import android.os.vibrator.VibrationEffectSegment;
-import android.util.MathUtils;
-import java.util.ArrayList;
import java.util.List;
/**
* Adapter that converts step segments that should be handled as PWLEs to ramp segments.
*
- * Each replaced {@link StepSegment} will be represented by a {@link RampSegment} with same
- * start and end amplitudes/frequencies, which can then be converted to PWLE compositions. This
- * adapter leaves the segments unchanged if the device doesn't have the PWLE composition capability.
+ *
Each replaced step will be represented by a ramp with same start and end
+ * amplitudes/frequencies, which can then be converted to PWLE compositions.
+ *
+ *
The segments will not be changed if the device doesn't have
+ * {@link IVibrator#CAP_COMPOSE_PWLE_EFFECTS}.
*/
final class StepToRampAdapter implements VibrationSegmentsAdapter {
@@ -42,12 +42,6 @@ final class StepToRampAdapter implements VibrationSegmentsAdapter {
// The vibrator does not have PWLE capability, so keep the segments unchanged.
return repeatIndex;
}
- convertStepsToRamps(info, segments);
- repeatIndex = splitLongRampSegments(info, segments, repeatIndex);
- return repeatIndex;
- }
-
- private void convertStepsToRamps(VibratorInfo info, List segments) {
int segmentCount = segments.size();
// Convert steps that require frequency control to ramps.
for (int i = 0; i < segmentCount; i++) {
@@ -68,40 +62,6 @@ final class StepToRampAdapter implements VibrationSegmentsAdapter {
}
}
}
- }
-
- /**
- * Split {@link RampSegment} entries that have duration longer than {@link
- * VibratorInfo#getPwlePrimitiveDurationMax()}.
- */
- private int splitLongRampSegments(VibratorInfo info, List segments,
- int repeatIndex) {
- int maxDuration = info.getPwlePrimitiveDurationMax();
- if (maxDuration <= 0) {
- // No limit set to PWLE primitive duration.
- return repeatIndex;
- }
-
- int segmentCount = segments.size();
- for (int i = 0; i < segmentCount; i++) {
- if (!(segments.get(i) instanceof RampSegment)) {
- continue;
- }
- RampSegment ramp = (RampSegment) segments.get(i);
- int splits = ((int) ramp.getDuration() + maxDuration - 1) / maxDuration;
- if (splits <= 1) {
- continue;
- }
- segments.remove(i);
- segments.addAll(i, splitRampSegment(info, ramp, splits));
- int addedSegments = splits - 1;
- if (repeatIndex > i) {
- repeatIndex += addedSegments;
- }
- i += addedSegments;
- segmentCount += addedSegments;
- }
-
return repeatIndex;
}
@@ -111,38 +71,6 @@ final class StepToRampAdapter implements VibrationSegmentsAdapter {
frequencyHz, frequencyHz, (int) segment.getDuration());
}
- private static List splitRampSegment(VibratorInfo info, RampSegment ramp,
- int splits) {
- List ramps = new ArrayList<>(splits);
- float startFrequencyHz = fillEmptyFrequency(info, ramp.getStartFrequencyHz());
- float endFrequencyHz = fillEmptyFrequency(info, ramp.getEndFrequencyHz());
- long splitDuration = ramp.getDuration() / splits;
- float previousAmplitude = ramp.getStartAmplitude();
- float previousFrequency = startFrequencyHz;
- long accumulatedDuration = 0;
-
- for (int i = 1; i < splits; i++) {
- accumulatedDuration += splitDuration;
- float durationRatio = (float) accumulatedDuration / ramp.getDuration();
- float interpolatedFrequency =
- MathUtils.lerp(startFrequencyHz, endFrequencyHz, durationRatio);
- float interpolatedAmplitude =
- MathUtils.lerp(ramp.getStartAmplitude(), ramp.getEndAmplitude(), durationRatio);
- RampSegment rampSplit = new RampSegment(
- previousAmplitude, interpolatedAmplitude,
- previousFrequency, interpolatedFrequency,
- (int) splitDuration);
- ramps.add(rampSplit);
- previousAmplitude = rampSplit.getEndAmplitude();
- previousFrequency = rampSplit.getEndFrequencyHz();
- }
-
- ramps.add(new RampSegment(previousAmplitude, ramp.getEndAmplitude(), previousFrequency,
- endFrequencyHz, (int) (ramp.getDuration() - accumulatedDuration)));
-
- return ramps;
- }
-
private static boolean isStep(VibrationEffectSegment segment) {
return segment instanceof StepSegment;
}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/RampToStepAdapterTest.java b/services/tests/vibrator/src/com/android/server/vibrator/RampToStepAdapterTest.java
index 8bb21b3af4485..867c061151b47 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/RampToStepAdapterTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/RampToStepAdapterTest.java
@@ -66,6 +66,9 @@ public class RampToStepAdapterTest {
assertEquals(-1, mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, -1));
assertEquals(1, mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, 1));
+ assertEquals(-1, mAdapter.adaptToVibrator(PWLE_VIBRATOR_INFO, segments, -1));
+ assertEquals(1, mAdapter.adaptToVibrator(PWLE_VIBRATOR_INFO, segments, 1));
+
assertEquals(originalSegments, segments);
}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/SplitSegmentsAdapterTest.java b/services/tests/vibrator/src/com/android/server/vibrator/SplitSegmentsAdapterTest.java
new file mode 100644
index 0000000000000..6630ccad61894
--- /dev/null
+++ b/services/tests/vibrator/src/com/android/server/vibrator/SplitSegmentsAdapterTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.hardware.vibrator.IVibrator;
+import android.os.VibrationEffect;
+import android.os.VibratorInfo;
+import android.os.vibrator.PrebakedSegment;
+import android.os.vibrator.PrimitiveSegment;
+import android.os.vibrator.RampSegment;
+import android.os.vibrator.StepSegment;
+import android.os.vibrator.VibrationEffectSegment;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.IntStream;
+
+public class SplitSegmentsAdapterTest {
+ private static final int PWLE_COMPOSITION_PRIMITIVE_DURATION_MAX = 10;
+
+ private static final float[] TEST_AMPLITUDE_MAP = new float[]{
+ /* 50Hz= */ 0.1f, 0.2f, 0.4f, 0.8f, /* 150Hz= */ 1f, 0.9f, /* 200Hz= */ 0.8f};
+
+ private static final VibratorInfo.FrequencyProfile TEST_FREQUENCY_PROFILE =
+ new VibratorInfo.FrequencyProfile(
+ /* resonantFrequencyHz= */ 150f, /* minFrequencyHz= */ 50f,
+ /* frequencyResolutionHz= */ 25f, TEST_AMPLITUDE_MAP);
+
+ private static final VibratorInfo EMPTY_VIBRATOR_INFO = createVibratorInfo();
+ private static final VibratorInfo PWLE_VIBRATOR_INFO = createVibratorInfo(
+ IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+
+ private SplitSegmentsAdapter mAdapter;
+
+ @Before
+ public void setUp() throws Exception {
+ mAdapter = new SplitSegmentsAdapter();
+ }
+
+ @Test
+ public void testStepAndPrebakedAndPrimitiveSegments_returnsOriginalSegments() {
+ List segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 1, /* frequencyHz= */ 40f, /* duration= */ 100),
+ new PrebakedSegment(
+ VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_LIGHT),
+ new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 10)));
+ List originalSegments = new ArrayList<>(segments);
+
+ assertThat(mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, /*repeatIndex= */ -1))
+ .isEqualTo(-1);
+ assertThat(mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, /*repeatIndex= */ 1))
+ .isEqualTo(1);
+
+ assertThat(mAdapter.adaptToVibrator(PWLE_VIBRATOR_INFO, segments, /*repeatIndex= */ -1))
+ .isEqualTo(-1);
+ assertThat(mAdapter.adaptToVibrator(PWLE_VIBRATOR_INFO, segments, /*repeatIndex= */ 1))
+ .isEqualTo(1);
+
+ assertThat(segments).isEqualTo(originalSegments);
+ }
+
+ @Test
+ public void testRampSegments_noPwleCapabilities_returnsOriginalSegments() {
+ List segments = new ArrayList<>(Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
+ /* startFrequencyHz= */ 10, /* endFrequencyHz= */ 10, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0.2f, /* endAmplitude*/ 0.8f,
+ /* startFrequencyHz= */ 60, /* endFrequencyHz= */ 90, /* duration= */ 10)));
+ List originalSegments = new ArrayList<>(segments);
+
+ assertThat(mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, /*repeatIndex= */ -1))
+ .isEqualTo(-1);
+ assertThat(mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, /*repeatIndex= */ 1))
+ .isEqualTo(1);
+
+ assertThat(segments).isEqualTo(originalSegments);
+ }
+
+ @Test
+ public void testRampSegments_withPwleDurationLimit_splitsLongRampsAndPreserveOtherSegments() {
+ List segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 1, /* frequencyHz= */ 40f, /* duration= */ 100),
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
+ /* startFrequencyHz= */ 10, /* endFrequencyHz= */ 10, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 1,
+ /* startFrequencyHz= */ 0, /* endFrequencyHz= */ 50, /* duration= */ 25),
+ new StepSegment(/* amplitude= */ 1, /* frequencyHz= */ 40f, /* duration= */ 100),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude*/ 1,
+ /* startFrequencyHz= */ 10, /* endFrequencyHz= */ 20, /* duration= */ 5)));
+ List expectedSegments = Arrays.asList(
+ new StepSegment(/* amplitude= */ 1, /* frequencyHz= */ 40f, /* duration= */ 100),
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
+ /* startFrequencyHz= */ 10, /* endFrequencyHz= */ 10, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0.32f,
+ /* startFrequencyHz= */ 150, /* endFrequencyHz= */ 118f, /* duration= */ 8),
+ new RampSegment(/* startAmplitude= */ 0.32f, /* endAmplitude= */ 0.64f,
+ /* startFrequencyHz= */ 118f, /* endFrequencyHz= */ 86f,
+ /* duration= */ 8),
+ new RampSegment(/* startAmplitude= */ 0.64f, /* endAmplitude= */ 1,
+ /* startFrequencyHz= */ 86f, /* endFrequencyHz= */ 50f, /* duration= */ 9),
+ new StepSegment(/* amplitude= */ 1, /* frequencyHz= */ 40f, /* duration= */ 100),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude*/ 1,
+ /* startFrequencyHz= */ 10, /* endFrequencyHz= */ 20, /* duration= */ 5));
+
+ VibratorInfo vibratorInfo = new VibratorInfo.Builder(0)
+ .setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)
+ .setPwlePrimitiveDurationMax(10)
+ .setFrequencyProfile(TEST_FREQUENCY_PROFILE)
+ .build();
+
+ // Update repeat index to skip the ramp splits.
+ assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ 3))
+ .isEqualTo(5);
+ assertThat(segments).isEqualTo(expectedSegments);
+ }
+
+ private static VibratorInfo createVibratorInfo(int... capabilities) {
+ return new VibratorInfo.Builder(0)
+ .setCapabilities(IntStream.of(capabilities).reduce((a, b) -> a | b).orElse(0))
+ .setFrequencyProfile(TEST_FREQUENCY_PROFILE)
+ .setPwlePrimitiveDurationMax(PWLE_COMPOSITION_PRIMITIVE_DURATION_MAX)
+ .build();
+ }
+}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/StepToRampAdapterTest.java b/services/tests/vibrator/src/com/android/server/vibrator/StepToRampAdapterTest.java
index 58deeecd35c9c..82deff011e82b 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/StepToRampAdapterTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/StepToRampAdapterTest.java
@@ -66,42 +66,12 @@ public class StepToRampAdapterTest {
assertEquals(-1, mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, -1));
assertEquals(1, mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, 1));
+ assertEquals(-1, mAdapter.adaptToVibrator(PWLE_VIBRATOR_INFO, segments, -1));
+ assertEquals(1, mAdapter.adaptToVibrator(PWLE_VIBRATOR_INFO, segments, 1));
+
assertEquals(originalSegments, segments);
}
- @Test
- public void testRampSegments_withPwleDurationLimit_splitsLongRamps() {
- List segments = new ArrayList<>(Arrays.asList(
- new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
- /* startFrequencyHz= */ 10, /* endFrequencyHz= */ 10, /* duration= */ 10),
- new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 1,
- /* startFrequencyHz= */ 0, /* endFrequencyHz= */ 50, /* duration= */ 25),
- new RampSegment(/* startAmplitude= */ 1, /* endAmplitude*/ 1,
- /* startFrequencyHz= */ 10, /* endFrequencyHz= */ 20, /* duration= */ 5)));
- List expectedSegments = Arrays.asList(
- new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
- /* startFrequencyHz= */ 10, /* endFrequencyHz= */ 10, /* duration= */ 10),
- new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0.32f,
- /* startFrequencyHz= */ 150, /* endFrequencyHz= */ 118f, /* duration= */ 8),
- new RampSegment(/* startAmplitude= */ 0.32f, /* endAmplitude= */ 0.64f,
- /* startFrequencyHz= */ 118f, /* endFrequencyHz= */ 86f,
- /* duration= */ 8),
- new RampSegment(/* startAmplitude= */ 0.64f, /* endAmplitude= */ 1,
- /* startFrequencyHz= */ 86f, /* endFrequencyHz= */ 50f, /* duration= */ 9),
- new RampSegment(/* startAmplitude= */ 1, /* endAmplitude*/ 1,
- /* startFrequencyHz= */ 10, /* endFrequencyHz= */ 20, /* duration= */ 5));
-
- VibratorInfo vibratorInfo = new VibratorInfo.Builder(0)
- .setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)
- .setPwlePrimitiveDurationMax(10)
- .setFrequencyProfile(TEST_FREQUENCY_PROFILE)
- .build();
-
- // Update repeat index to skip the ramp splits.
- assertEquals(4, mAdapter.adaptToVibrator(vibratorInfo, segments, 2));
- assertEquals(expectedSegments, segments);
- }
-
@Test
public void testStepAndRampSegments_withoutPwleCapability_keepsListUnchanged() {
List segments = new ArrayList<>(Arrays.asList(