Merge "Use PWLE for waveforms and add ramp down to zero" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
5bb0024e1f
@@ -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.
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
VibrationEffect.Composed adaptedEffect = (VibrationEffect.Composed) mAdapter.apply(effect,
|
||||
createVibratorInfo(EMPTY_FREQUENCY_MAPPING));
|
||||
assertTrue(adaptedEffect.getSegments().size() > effect.getSegments().size());
|
||||
assertTrue(adaptedEffect.getRepeatIndex() >= effect.getRepeatIndex());
|
||||
|
||||
VibratorInfo info = createVibratorInfo(EMPTY_FREQUENCY_MAPPING);
|
||||
assertEquals(expected, mAdapter.apply(effect, info));
|
||||
for (VibrationEffectSegment adaptedSegment : adaptedEffect.getSegments()) {
|
||||
assertTrue(adaptedSegment instanceof StepSegment);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -135,33 +130,6 @@ public class DeviceVibrationEffectAdapterTest {
|
||||
assertEquals(expected, mAdapter.apply(effect, info));
|
||||
}
|
||||
|
||||
@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(
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user