summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Lais Andrade <lsandrade@google.com> 2021-05-26 13:32:05 +0100
committer Lais Andrade <lsandrade@google.com> 2021-06-15 19:37:56 +0100
commit11e3bb7af7813548a0e2cfa3a80f44a00ce0b4cf (patch)
tree188c0b4968e272ba8cc383f897e024946070a716
parent50ae7cbf1bdd18a23c14b82037af9705c4524470 (diff)
Use PWLE for waveforms and add ramp down to zero
Add new configuration for ramp down duration (defaults to zero) to be used by devices that require a soft ramp down to zero amplitude between two segments when the change is abrupt to zero. The waveform timings will be respected, so the ramp down duration might be reduced if the waveform segment with zero amplitude is shorter than the configured ramp duration. This does not add a ramp at the end of vibrations. This will be done in a follow up. Bug: 188431691 Test: StepToRampAdapterTest Change-Id: I9af8c653462defaa1fc26a4fe60077a63831f3fe
-rw-r--r--core/res/res/values/config.xml9
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java12
-rw-r--r--services/core/java/com/android/server/vibrator/RampToStepAdapter.java2
-rw-r--r--services/core/java/com/android/server/vibrator/StepToRampAdapter.java196
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationThread.java10
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/DeviceVibrationEffectAdapterTest.java62
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/RampToStepAdapterTest.java122
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java312
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java11
11 files changed, 673 insertions, 71 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5ac23365eaee..ee33d48768c5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3354,6 +3354,15 @@
(e.g. accessibility, alarms). This is mainly for Wear devices that don't have speakers. -->
<bool name="config_allowPriorityVibrationsInLowPowerMode">false</bool>
+ <!-- The duration (in milliseconds) that should be used to convert vibration ramps to a sequence
+ of fixed amplitude steps on devices without PWLE support. -->
+ <integer name="config_vibrationWaveformRampStepDuration">5</integer>
+
+ <!-- The duration (in milliseconds) that should be applied to waveform vibrations that ends in
+ non-zero amplitudes, . The waveform will
+ be played as a PWLE instead of on/off calls if this value is set. -->
+ <integer name="config_vibrationWaveformRampDownDuration">0</integer>
+
<!-- Number of retries Cell Data should attempt for a given error code before
restarting the modem.
Error codes not listed will not lead to modem restarts.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b574415c0a08..7d685a202538 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2012,6 +2012,8 @@
<java-symbol type="integer" name="config_notificationServiceArchiveSize" />
<java-symbol type="integer" name="config_previousVibrationsDumpLimit" />
<java-symbol type="integer" name="config_defaultVibrationAmplitude" />
+ <java-symbol type="integer" name="config_vibrationWaveformRampStepDuration" />
+ <java-symbol type="integer" name="config_vibrationWaveformRampDownDuration" />
<java-symbol type="integer" name="config_radioScanningTimeout" />
<java-symbol type="integer" name="config_screenBrightnessSettingMinimum" />
<java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
diff --git a/services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java b/services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java
index b695150d9ba3..e8ce4f336caa 100644
--- a/services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java
+++ b/services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java
@@ -16,6 +16,7 @@
package com.android.server.vibrator;
+import android.content.Context;
import android.os.VibrationEffect;
import android.os.VibratorInfo;
@@ -26,17 +27,16 @@ import java.util.List;
final class DeviceVibrationEffectAdapter
implements VibrationEffectAdapters.EffectAdapter<VibratorInfo> {
- /** Duration of each step created to simulate a ramp segment. */
- private static final int RAMP_STEP_DURATION_MILLIS = 5;
-
private final List<VibrationEffectAdapters.SegmentsAdapter<VibratorInfo>> mSegmentAdapters;
- DeviceVibrationEffectAdapter() {
+ DeviceVibrationEffectAdapter(Context context) {
mSegmentAdapters = Arrays.asList(
// TODO(b/167947076): add filter that removes unsupported primitives
// TODO(b/167947076): add filter that replaces unsupported prebaked with fallback
- new RampToStepAdapter(RAMP_STEP_DURATION_MILLIS),
- new StepToRampAdapter(),
+ new RampToStepAdapter(context.getResources().getInteger(
+ com.android.internal.R.integer.config_vibrationWaveformRampStepDuration)),
+ new StepToRampAdapter(context.getResources().getInteger(
+ com.android.internal.R.integer.config_vibrationWaveformRampDownDuration)),
new ClippingAmplitudeAndFrequencyAdapter()
);
}
diff --git a/services/core/java/com/android/server/vibrator/RampToStepAdapter.java b/services/core/java/com/android/server/vibrator/RampToStepAdapter.java
index 1e05bdbdf082..64624a28c5da 100644
--- a/services/core/java/com/android/server/vibrator/RampToStepAdapter.java
+++ b/services/core/java/com/android/server/vibrator/RampToStepAdapter.java
@@ -29,7 +29,7 @@ import java.util.List;
/**
* Adapter that converts ramp segments that to a sequence of fixed step segments.
*
- * <p>This leaves the list unchanged if the device have compose PWLE capability.
+ * <p>This leaves the list unchanged if the device has compose PWLE capability.
*/
final class RampToStepAdapter implements VibrationEffectAdapters.SegmentsAdapter<VibratorInfo> {
diff --git a/services/core/java/com/android/server/vibrator/StepToRampAdapter.java b/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
index f78df9208fbd..d439b94ec2fc 100644
--- a/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
+++ b/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
@@ -27,39 +27,221 @@ import java.util.List;
/**
* Adapter that converts step segments that should be handled as PWLEs to ramp segments.
*
- * <p>This leaves the list unchanged if the device do not have compose PWLE capability.
+ * <p>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.
+ *
+ * <p>This adapter also applies the ramp down duration config on devices with PWLE support. This
+ * prevents the device from ringing when it cannot handle abrupt changes between ON and OFF states.
+ * This will not change other types of abrupt amplitude changes in the original effect.
+ *
+ * <p>The effect overall duration is preserved by this transformation. Waveforms with ON/OFF
+ * segments are handled gracefully by the ramp down changes. Each OFF segment preceded by an ON
+ * segment will be shortened, and a ramp down will be added to the transition between ON and OFF.
+ * The ramps can be shorter than the configured duration in order to preserve the waveform timings,
+ * but they will still soften the ringing effect.
*/
final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter<VibratorInfo> {
+
+ private final int mRampDownDuration;
+
+ StepToRampAdapter(int rampDownDuration) {
+ mRampDownDuration = rampDownDuration;
+ }
+
@Override
public int apply(List<VibrationEffectSegment> segments, int repeatIndex,
VibratorInfo info) {
if (!info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
- // The vibrator do not have PWLE capability, so keep the segments unchanged.
+ // The vibrator does not have PWLE capability, so keep the segments unchanged.
return repeatIndex;
}
+ convertStepsToRamps(segments);
+ int newRepeatIndex = addRampDownToZeroAmplitudeSegments(segments, repeatIndex);
+ newRepeatIndex = addRampDownToLoop(segments, newRepeatIndex);
+ return newRepeatIndex;
+ }
+
+ private void convertStepsToRamps(List<VibrationEffectSegment> segments) {
int segmentCount = segments.size();
+ if (mRampDownDuration > 0) {
+ // Convert all steps to ramps if the device requires ramp down.
+ for (int i = 0; i < segmentCount; i++) {
+ if (isStep(segments.get(i))) {
+ segments.set(i, apply((StepSegment) segments.get(i)));
+ }
+ }
+ return;
+ }
// Convert steps that require frequency control to ramps.
for (int i = 0; i < segmentCount; i++) {
VibrationEffectSegment segment = segments.get(i);
- if ((segment instanceof StepSegment)
- && ((StepSegment) segment).getFrequency() != 0) {
+ if (isStep(segment) && ((StepSegment) segment).getFrequency() != 0) {
segments.set(i, apply((StepSegment) segment));
}
}
// Convert steps that are next to ramps to also become ramps, so they can be composed
// together in the same PWLE waveform.
- for (int i = 1; i < segmentCount; i++) {
+ for (int i = 0; i < segmentCount; i++) {
if (segments.get(i) instanceof RampSegment) {
- for (int j = i - 1; j >= 0 && (segments.get(j) instanceof StepSegment); j--) {
+ for (int j = i - 1; j >= 0 && isStep(segments.get(j)); j--) {
segments.set(j, apply((StepSegment) segments.get(j)));
}
+ for (int j = i + 1; j < segmentCount && isStep(segments.get(j)); j++) {
+ segments.set(j, apply((StepSegment) segments.get(j)));
+ }
+ }
+ }
+ }
+
+ /**
+ * This will add a ramp to zero as follows:
+ *
+ * <ol>
+ * <li>Remove the {@link VibrationEffectSegment} that starts and ends at zero amplitude
+ * and follows a segment that ends at non-zero amplitude;
+ * <li>Add a ramp down to zero starting at the previous segment end amplitude and frequency,
+ * with min between the removed segment duration and the configured ramp down duration;
+ * <li>Add a zero amplitude segment following the ramp with the remaining duration, if
+ * necessary;
+ * </ol>
+ */
+ private int addRampDownToZeroAmplitudeSegments(List<VibrationEffectSegment> segments,
+ int repeatIndex) {
+ if (mRampDownDuration <= 0) {
+ // Nothing to do, no ramp down duration configured.
+ return repeatIndex;
+ }
+ int newRepeatIndex = repeatIndex;
+ int newSegmentCount = segments.size();
+ for (int i = 1; i < newSegmentCount; i++) {
+ if (!isOffRampSegment(segments.get(i))
+ || !endsWithNonZeroAmplitude(segments.get(i - 1))) {
+ continue;
+ }
+
+ // We know the previous segment is a ramp that ends at non-zero amplitude.
+ float previousAmplitude = ((RampSegment) segments.get(i - 1)).getEndAmplitude();
+ float previousFrequency = ((RampSegment) segments.get(i - 1)).getEndFrequency();
+ RampSegment ramp = (RampSegment) segments.get(i);
+
+ if (ramp.getDuration() <= mRampDownDuration) {
+ // Replace the zero amplitude segment with a ramp down of same duration, to
+ // preserve waveform timings and still soften the transition to zero.
+ segments.set(i, createRampDown(previousAmplitude, previousFrequency,
+ ramp.getDuration()));
+ } else {
+ // Make the zero amplitude segment shorter, to preserve waveform timings, and add a
+ // ramp down to zero segment right before it.
+ segments.set(i, updateDuration(ramp, ramp.getDuration() - mRampDownDuration));
+ segments.add(i, createRampDown(previousAmplitude, previousFrequency,
+ mRampDownDuration));
+ if (repeatIndex > i) {
+ newRepeatIndex++;
+ }
+ i++;
+ newSegmentCount++;
+ }
+ }
+ return newRepeatIndex;
+ }
+
+ /**
+ * This will add a ramp to zero at the repeating index of the given effect, if set, only if
+ * the last segment ends at a non-zero amplitude and the repeating segment starts and ends at
+ * zero amplitude. The update is described as:
+ *
+ * <ol>
+ * <li>Add a ramp down to zero following the last segment, with the min between the
+ * removed segment duration and the configured ramp down duration;
+ * <li>Skip the zero-amplitude segment by incrementing the repeat index, splitting it if
+ * necessary to skip the correct amount;
+ * </ol>
+ */
+ private int addRampDownToLoop(List<VibrationEffectSegment> segments, int repeatIndex) {
+ if (repeatIndex < 0) {
+ // Non-repeating compositions should remain unchanged so duration will be preserved.
+ return repeatIndex;
+ }
+
+ int segmentCount = segments.size();
+ if (mRampDownDuration <= 0 || !endsWithNonZeroAmplitude(segments.get(segmentCount - 1))) {
+ // Nothing to do, no ramp down duration configured or composition already ends at zero.
+ return repeatIndex;
+ }
+
+ // We know the last segment is a ramp that ends at non-zero amplitude.
+ RampSegment lastRamp = (RampSegment) segments.get(segmentCount - 1);
+ float previousAmplitude = lastRamp.getEndAmplitude();
+ float previousFrequency = lastRamp.getEndFrequency();
+
+ if (isOffRampSegment(segments.get(repeatIndex))) {
+ // Repeating from a non-zero to a zero amplitude segment, we know the next segment is a
+ // ramp with zero amplitudes.
+ RampSegment nextRamp = (RampSegment) segments.get(repeatIndex);
+
+ if (nextRamp.getDuration() <= mRampDownDuration) {
+ // Skip the zero amplitude segment and append a ramp down of same duration to the
+ // end of the composition, to preserve waveform timings and still soften the
+ // transition to zero.
+ // This will update the waveform as follows:
+ // R R+1
+ // | ____ | ____
+ // _|_/ => __|/ \
+ segments.add(createRampDown(previousAmplitude, previousFrequency,
+ nextRamp.getDuration()));
+ repeatIndex++;
+ } else {
+ // Append a ramp down to the end of the composition, split the zero amplitude
+ // segment and start repeating from the second half, to preserve waveform timings.
+ // This will update the waveform as follows:
+ // R R+1
+ // | ____ | ____
+ // _|__/ => __|_/ \
+ segments.add(createRampDown(previousAmplitude, previousFrequency,
+ mRampDownDuration));
+ segments.set(repeatIndex, updateDuration(nextRamp,
+ nextRamp.getDuration() - mRampDownDuration));
+ segments.add(repeatIndex, updateDuration(nextRamp, mRampDownDuration));
+ repeatIndex++;
}
}
+
return repeatIndex;
}
- private RampSegment apply(StepSegment segment) {
+ private static RampSegment apply(StepSegment segment) {
return new RampSegment(segment.getAmplitude(), segment.getAmplitude(),
segment.getFrequency(), segment.getFrequency(), (int) segment.getDuration());
}
+
+ private static RampSegment createRampDown(float amplitude, float frequency, long duration) {
+ return new RampSegment(amplitude, /* endAmplitude= */ 0, frequency, frequency,
+ (int) duration);
+ }
+
+ private static RampSegment updateDuration(RampSegment ramp, long newDuration) {
+ return new RampSegment(ramp.getStartAmplitude(), ramp.getEndAmplitude(),
+ ramp.getStartFrequency(), ramp.getEndFrequency(), (int) newDuration);
+ }
+
+ private static boolean isStep(VibrationEffectSegment segment) {
+ return segment instanceof StepSegment;
+ }
+
+ /** Returns true if the segment is a ramp that starts and ends at zero amplitude. */
+ private static boolean isOffRampSegment(VibrationEffectSegment segment) {
+ if (segment instanceof RampSegment) {
+ RampSegment ramp = (RampSegment) segment;
+ return ramp.getStartAmplitude() == 0 && ramp.getEndAmplitude() == 0;
+ }
+ return false;
+ }
+
+ private static boolean endsWithNonZeroAmplitude(VibrationEffectSegment segment) {
+ if (segment instanceof RampSegment) {
+ return ((RampSegment) segment).getEndAmplitude() != 0;
+ }
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index e3672f4d497c..150fde99b706 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -95,8 +95,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
private final WorkSource mWorkSource = new WorkSource();
private final PowerManager.WakeLock mWakeLock;
private final IBatteryStats mBatteryStatsService;
- private final DeviceVibrationEffectAdapter mDeviceEffectAdapter =
- new DeviceVibrationEffectAdapter();
+ private final DeviceVibrationEffectAdapter mDeviceEffectAdapter;
private final Vibration mVibration;
private final VibrationCallbacks mCallbacks;
private final SparseArray<VibratorController> mVibrators = new SparseArray<>();
@@ -104,10 +103,11 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
private volatile boolean mForceStop;
- VibrationThread(Vibration vib, SparseArray<VibratorController> availableVibrators,
- PowerManager.WakeLock wakeLock, IBatteryStats batteryStatsService,
- VibrationCallbacks callbacks) {
+ VibrationThread(Vibration vib, DeviceVibrationEffectAdapter effectAdapter,
+ SparseArray<VibratorController> availableVibrators, PowerManager.WakeLock wakeLock,
+ IBatteryStats batteryStatsService, VibrationCallbacks callbacks) {
mVibration = vib;
+ mDeviceEffectAdapter = effectAdapter;
mCallbacks = callbacks;
mWakeLock = wakeLock;
mWorkSource.set(vib.uid);
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 06a5077bec82..2f0ed19d867a 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -132,6 +132,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
private final VibrationSettings mVibrationSettings;
private final VibrationScaler mVibrationScaler;
private final InputDeviceDelegate mInputDeviceDelegate;
+ private final DeviceVibrationEffectAdapter mDeviceVibrationEffectAdapter;
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
@@ -175,6 +176,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
mVibrationSettings = new VibrationSettings(mContext, mHandler);
mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings);
mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler);
+ mDeviceVibrationEffectAdapter = new DeviceVibrationEffectAdapter(mContext);
VibrationCompleteListener listener = new VibrationCompleteListener(this);
mNativeWrapper = injector.getNativeWrapper();
@@ -512,8 +514,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
return Vibration.Status.FORWARDED_TO_INPUT_DEVICES;
}
- VibrationThread vibThread = new VibrationThread(vib, mVibrators, mWakeLock,
- mBatteryStatsService, mVibrationCallbacks);
+ VibrationThread vibThread = new VibrationThread(vib, mDeviceVibrationEffectAdapter,
+ mVibrators, mWakeLock, mBatteryStatsService, mVibrationCallbacks);
if (mCurrentVibration == null) {
return startVibrationThreadLocked(vibThread);
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/DeviceVibrationEffectAdapterTest.java b/services/tests/servicestests/src/com/android/server/vibrator/DeviceVibrationEffectAdapterTest.java
index 00b05d4ad10c..14cab021edb0 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/DeviceVibrationEffectAdapterTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/DeviceVibrationEffectAdapterTest.java
@@ -17,6 +17,7 @@
package com.android.server.vibrator;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.hardware.vibrator.IVibrator;
import android.os.VibrationEffect;
@@ -25,8 +26,11 @@ 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 android.platform.test.annotations.Presubmit;
+import androidx.test.InstrumentationRegistry;
+
import org.junit.Before;
import org.junit.Test;
@@ -58,7 +62,7 @@ public class DeviceVibrationEffectAdapterTest {
@Before
public void setUp() throws Exception {
- mAdapter = new DeviceVibrationEffectAdapter();
+ mAdapter = new DeviceVibrationEffectAdapter(InstrumentationRegistry.getContext());
}
@Test
@@ -84,28 +88,19 @@ public class DeviceVibrationEffectAdapterTest {
new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 0.2f,
/* startFrequency= */ -4, /* endFrequency= */ 2, /* duration= */ 10),
new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f,
- /* startFrequency= */ 0, /* endFrequency= */ 0, /* duration= */ 11),
+ /* startFrequency= */ 0, /* endFrequency= */ 0, /* duration= */ 100),
new RampSegment(/* startAmplitude= */ 0.65f, /* endAmplitude= */ 0.65f,
- /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 200)),
+ /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 1000)),
/* repeatIndex= */ 3);
- VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList(
- new StepSegment(/* amplitude= */ 0, Float.NaN, /* duration= */ 10),
- new StepSegment(/* amplitude= */ 0.5f, Float.NaN, /* duration= */ 100),
- // 10ms ramp becomes 2 steps
- new StepSegment(/* amplitude= */ 1, Float.NaN, /* duration= */ 5),
- new StepSegment(/* amplitude= */ 0.2f, Float.NaN, /* duration= */ 5),
- // 11ms ramp becomes 3 steps
- new StepSegment(/* amplitude= */ 0.8f, Float.NaN, /* duration= */ 5),
- new StepSegment(/* amplitude= */ 0.6f, Float.NaN, /* duration= */ 5),
- new StepSegment(/* amplitude= */ 0.2f, Float.NaN, /* duration= */ 1),
- // 200ms ramp with same amplitude becomes a single step
- new StepSegment(/* amplitude= */ 0.65f, Float.NaN, /* duration= */ 200)),
- // Repeat index fixed after intermediate steps added
- /* repeatIndex= */ 4);
-
- VibratorInfo info = createVibratorInfo(EMPTY_FREQUENCY_MAPPING);
- assertEquals(expected, mAdapter.apply(effect, info));
+ VibrationEffect.Composed adaptedEffect = (VibrationEffect.Composed) mAdapter.apply(effect,
+ createVibratorInfo(EMPTY_FREQUENCY_MAPPING));
+ assertTrue(adaptedEffect.getSegments().size() > effect.getSegments().size());
+ assertTrue(adaptedEffect.getRepeatIndex() >= effect.getRepeatIndex());
+
+ for (VibrationEffectSegment adaptedSegment : adaptedEffect.getSegments()) {
+ assertTrue(adaptedSegment instanceof StepSegment);
+ }
}
@Test
@@ -136,33 +131,6 @@ public class DeviceVibrationEffectAdapterTest {
}
@Test
- public void testStepAndRampSegments_withPwleCapabilityAndNoFrequency_keepsOriginalSteps() {
- VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
- new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 10),
- new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100),
- new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 10),
- new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
- /* startFrequency= */ -4, /* endFrequency= */ 2, /* duration= */ 50),
- new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f,
- /* startFrequency= */ 10, /* endFrequency= */ -5, /* duration= */ 20)),
- /* repeatIndex= */ 2);
-
- VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList(
- new StepSegment(/* amplitude= */ 0, /* frequency= */ 150, /* duration= */ 10),
- new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 150, /* duration= */ 100),
- new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 10),
- new RampSegment(/* startAmplitude= */ 0.1f, /* endAmplitude= */ 0.8f,
- /* startFrequency= */ 50, /* endFrequency= */ 200, /* duration= */ 50),
- new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.1f,
- /* startFrequency= */ 200, /* endFrequency= */ 50, /* duration= */ 20)),
- /* repeatIndex= */ 2);
-
- VibratorInfo info = createVibratorInfo(TEST_FREQUENCY_MAPPING,
- IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
- assertEquals(expected, mAdapter.apply(effect, info));
- }
-
- @Test
public void testStepAndRampSegments_withEmptyFreqMapping_returnsSameAmplitudesAndZeroFreq() {
VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10),
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/RampToStepAdapterTest.java b/services/tests/servicestests/src/com/android/server/vibrator/RampToStepAdapterTest.java
new file mode 100644
index 000000000000..95c3bd93e69b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/vibrator/RampToStepAdapterTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2021 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 org.junit.Assert.assertEquals;
+
+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 android.platform.test.annotations.Presubmit;
+
+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;
+
+/**
+ * Tests for {@link RampToStepAdapter}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:RampToStepAdapterTest
+ */
+@Presubmit
+public class RampToStepAdapterTest {
+ private static final int TEST_STEP_DURATION = 5;
+
+ private RampToStepAdapter mAdapter;
+
+ @Before
+ public void setUp() throws Exception {
+ mAdapter = new RampToStepAdapter(TEST_STEP_DURATION);
+ }
+
+ @Test
+ public void testStepAndPrebakedAndPrimitiveSegments_keepsListUnchanged() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10),
+ new PrebakedSegment(
+ VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_LIGHT),
+ new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 10)));
+ List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
+
+ assertEquals(-1, mAdapter.apply(segments, -1, createVibratorInfo()));
+ assertEquals(1, mAdapter.apply(segments, 1, createVibratorInfo()));
+
+ assertEquals(originalSegments, segments);
+ }
+
+ @Test
+ public void testRampSegments_withPwleCapability_keepsListUnchanged() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100),
+ new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f,
+ /* startFrequency= */ 10, /* endFrequency= */ -5, /* duration= */ 20)));
+ List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
+
+ VibratorInfo vibratorInfo = createVibratorInfo(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ assertEquals(-1, mAdapter.apply(segments, -1, vibratorInfo));
+ assertEquals(0, mAdapter.apply(segments, 0, vibratorInfo));
+
+ assertEquals(originalSegments, segments);
+ }
+
+ @Test
+ public void testRampSegments_withoutPwleCapability_convertsRampsToSteps() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 0.2f,
+ /* startFrequency= */ -4, /* endFrequency= */ 2, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f,
+ /* startFrequency= */ -3, /* endFrequency= */ 0, /* duration= */ 11),
+ new RampSegment(/* startAmplitude= */ 0.65f, /* endAmplitude= */ 0.65f,
+ /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 200)));
+
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100),
+ // 10ms ramp becomes 2 steps
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ -4, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0.2f, /* frequency= */ 2, /* duration= */ 5),
+ // 11ms ramp becomes 3 steps
+ new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ -3, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0.6f, /* frequency= */ -2, /* duration= */ 5),
+ new StepSegment(/* amplitude= */ 0.2f, /* frequency= */ 0, /* duration= */ 1),
+ // 200ms ramp with same amplitude becomes a single step
+ new StepSegment(/* amplitude= */ 0.65f, /* frequency= */ 0, /* duration= */ 200));
+
+ // Repeat index fixed after intermediate steps added
+ assertEquals(4, mAdapter.apply(segments, 3, createVibratorInfo()));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ private static VibratorInfo createVibratorInfo(int... capabilities) {
+ return new VibratorInfo.Builder(0)
+ .setCapabilities(IntStream.of(capabilities).reduce((a, b) -> a | b).orElse(0))
+ .build();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java b/services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java
new file mode 100644
index 000000000000..f4eb2ded5a9d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2021 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 org.junit.Assert.assertEquals;
+
+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 android.platform.test.annotations.Presubmit;
+
+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;
+
+/**
+ * Tests for {@link StepToRampAdapter}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:StepToRampAdapterTest
+ */
+@Presubmit
+public class StepToRampAdapterTest {
+ private StepToRampAdapter mAdapter;
+
+ @Before
+ public void setUp() throws Exception {
+ mAdapter = new StepToRampAdapter(/* rampDownDuration= */ 0);
+ }
+
+ @Test
+ public void testRampAndPrebakedAndPrimitiveSegments_returnsOriginalSegments() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 0.2f,
+ /* startFrequency= */ -4, /* endFrequency= */ 2, /* duration= */ 10),
+ new PrebakedSegment(
+ VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_LIGHT),
+ new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 10)));
+ List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
+
+ assertEquals(-1, mAdapter.apply(segments, -1, createVibratorInfo()));
+ assertEquals(1, mAdapter.apply(segments, 1, createVibratorInfo()));
+
+ assertEquals(originalSegments, segments);
+ }
+
+ @Test
+ public void testStepAndRampSegments_withoutPwleCapability_keepsListUnchanged() {
+ mAdapter = new StepToRampAdapter(50);
+
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f,
+ /* startFrequency= */ 10, /* endFrequency= */ -5, /* duration= */ 20)));
+ List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
+
+ assertEquals(-1, mAdapter.apply(segments, -1, createVibratorInfo()));
+ assertEquals(0, mAdapter.apply(segments, 0, createVibratorInfo()));
+
+ assertEquals(originalSegments, segments);
+ }
+
+ @Test
+ public void testStepAndRampSegments_withPwleCapabilityAndNoFrequency_keepsOriginalSteps() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100),
+ new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 10),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
+ /* startFrequency= */ -4, /* endFrequency= */ 2, /* duration= */ 50),
+ new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f,
+ /* startFrequency= */ 10, /* endFrequency= */ -5, /* duration= */ 20)));
+ List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
+
+ VibratorInfo vibratorInfo = createVibratorInfo(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ assertEquals(-1, mAdapter.apply(segments, -1, vibratorInfo));
+ assertEquals(3, mAdapter.apply(segments, 3, vibratorInfo));
+
+ assertEquals(originalSegments, segments);
+ }
+
+ @Test
+ public void testStepAndRampSegments_withPwleCapabilityAndStepNextToRamp_convertsStepsToRamps() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
+ /* startFrequency= */ -4, /* endFrequency= */ 2, /* duration= */ 50),
+ new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f,
+ /* startFrequency= */ 10, /* endFrequency= */ -5, /* duration= */ 20),
+ new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ -1, /* duration= */ 60)));
+
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0, /* endAmplitude*/ 0,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude= */ 0.5f,
+ /* startFrequency= */ 0, /* endFrequency= */ 0, /* duration= */ 100),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
+ /* startFrequency= */ -4, /* endFrequency= */ 2, /* duration= */ 50),
+ new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f,
+ /* startFrequency= */ 10, /* endFrequency= */ -5, /* duration= */ 20),
+ new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.8f,
+ /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 60));
+
+ VibratorInfo vibratorInfo = createVibratorInfo(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ assertEquals(-1, mAdapter.apply(segments, -1, vibratorInfo));
+ assertEquals(2, mAdapter.apply(segments, 2, vibratorInfo));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ public void testStepSegments_withPwleCapabilityAndFrequency_convertsStepsToRamps() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ -1, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 1, /* duration= */ 100)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0, /* endAmplitude*/ 0,
+ /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude= */ 0.5f,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 100));
+
+ VibratorInfo vibratorInfo = createVibratorInfo(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ assertEquals(-1, mAdapter.apply(segments, -1, vibratorInfo));
+ assertEquals(0, mAdapter.apply(segments, 0, vibratorInfo));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ public void testStepSegments_withRampDownEndingAtNonZero_noRampDownAdded() {
+ int rampDownDuration = 50;
+ mAdapter = new StepToRampAdapter(rampDownDuration);
+
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 1, /* duration= */ 100)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
+ /* startFrequency= */ 0, /* endFrequency= */ 0, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.8f,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 100));
+
+ VibratorInfo vibratorInfo = createVibratorInfo(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ assertEquals(-1, mAdapter.apply(segments, -1, vibratorInfo));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ public void testStepSegments_withRampDownAndShortZeroSegment_replaceWithRampDown() {
+ mAdapter = new StepToRampAdapter(50);
+
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ -1, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 20),
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 1, /* duration= */ 30)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
+ /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude= */ 0,
+ /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 20),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 30));
+
+ VibratorInfo vibratorInfo = createVibratorInfo(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ assertEquals(2, mAdapter.apply(segments, 2, vibratorInfo));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ public void testStepSegments_withRampDownAndLongZeroSegment_splitAndAddRampDown() {
+ mAdapter = new StepToRampAdapter(50);
+
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ -1, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 150),
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 1, /* duration= */ 30)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
+ /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude= */ 0,
+ /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 50),
+ new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 100),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 30));
+
+ VibratorInfo vibratorInfo = createVibratorInfo(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ // Repeat index fixed after intermediate steps added
+ assertEquals(3, mAdapter.apply(segments, 2, vibratorInfo));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ public void testStepSegments_withRampDownAndNoZeroSegment_noRampDownAdded() {
+ mAdapter = new StepToRampAdapter(50);
+
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ -1, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 1, /* duration= */ 30),
+ new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 10)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
+ /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 30),
+ new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 10));
+
+ VibratorInfo vibratorInfo = createVibratorInfo(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ assertEquals(-1, mAdapter.apply(segments, -1, vibratorInfo));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ public void testStepSegments_withRampDownAndRepeatToNonZeroSegment_noRampDownAdded() {
+ mAdapter = new StepToRampAdapter(50);
+
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ -1, /* duration= */ 10),
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 1, /* duration= */ 30)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
+ /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 30));
+
+ VibratorInfo vibratorInfo = createVibratorInfo(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ assertEquals(0, mAdapter.apply(segments, 0, vibratorInfo));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ public void testStepSegments_withRampDownAndRepeatToShortZeroSegment_skipAndAppendRampDown() {
+ mAdapter = new StepToRampAdapter(50);
+
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 20),
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 1, /* duration= */ 30)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0, /* endAmplitude*/ 0,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 20),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 30),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 0,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 20));
+
+ VibratorInfo vibratorInfo = createVibratorInfo(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ // Shift repeat index to the right to use append instead of zero segment.
+ assertEquals(1, mAdapter.apply(segments, 0, vibratorInfo));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
+ public void testStepSegments_withRampDownAndRepeatToLongZeroSegment_splitAndAppendRampDown() {
+ mAdapter = new StepToRampAdapter(50);
+
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 120),
+ new StepSegment(/* amplitude= */ 1, /* frequency= */ 1, /* duration= */ 30)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ // Split long zero segment to skip part of it.
+ new RampSegment(/* startAmplitude= */ 0, /* endAmplitude*/ 0,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 50),
+ new RampSegment(/* startAmplitude= */ 0, /* endAmplitude*/ 0,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 70),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 30),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 0,
+ /* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 50));
+
+ VibratorInfo vibratorInfo = createVibratorInfo(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ // Shift repeat index to the right to use append with part of the zero segment.
+ assertEquals(1, mAdapter.apply(segments, 0, vibratorInfo));
+
+ assertEquals(expectedSegments, segments);
+ }
+
+ private static VibratorInfo createVibratorInfo(int... capabilities) {
+ return new VibratorInfo.Builder(0)
+ .setCapabilities(IntStream.of(capabilities).reduce((a, b) -> a | b).orElse(0))
+ .build();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index ac3e05d27962..f02e2f081e3b 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
import android.hardware.vibrator.Braking;
import android.hardware.vibrator.IVibrator;
import android.hardware.vibrator.IVibratorManager;
@@ -98,13 +99,17 @@ public class VibrationThreadTest {
private IBatteryStats mIBatteryStatsMock;
private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
+ private DeviceVibrationEffectAdapter mEffectAdapter;
private PowerManager.WakeLock mWakeLock;
private TestLooper mTestLooper;
@Before
public void setUp() throws Exception {
mTestLooper = new TestLooper();
- mWakeLock = InstrumentationRegistry.getContext().getSystemService(
+
+ Context context = InstrumentationRegistry.getContext();
+ mEffectAdapter = new DeviceVibrationEffectAdapter(context);
+ mWakeLock = context.getSystemService(
PowerManager.class).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
mockVibrators(VIBRATOR_ID);
@@ -985,8 +990,8 @@ public class VibrationThreadTest {
}
private VibrationThread startThreadAndDispatcher(Vibration vib) {
- VibrationThread thread = new VibrationThread(vib, createVibratorControllers(), mWakeLock,
- mIBatteryStatsMock, mThreadCallbacks);
+ VibrationThread thread = new VibrationThread(vib, mEffectAdapter,
+ createVibratorControllers(), mWakeLock, mIBatteryStatsMock, mThreadCallbacks);
doAnswer(answer -> {
thread.vibratorComplete(answer.getArgument(0));
return null;