Merge "Use PWLE for waveforms and add ramp down to zero" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-06-15 20:50:45 +00:00
committed by Android (Google) Code Review
11 changed files with 672 additions and 70 deletions

View File

@@ -3354,6 +3354,15 @@
(e.g. accessibility, alarms). This is mainly for Wear devices that don't have speakers. --> (e.g. accessibility, alarms). This is mainly for Wear devices that don't have speakers. -->
<bool name="config_allowPriorityVibrationsInLowPowerMode">false</bool> <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 <!-- Number of retries Cell Data should attempt for a given error code before
restarting the modem. restarting the modem.
Error codes not listed will not lead to modem restarts. Error codes not listed will not lead to modem restarts.

View File

@@ -2012,6 +2012,8 @@
<java-symbol type="integer" name="config_notificationServiceArchiveSize" /> <java-symbol type="integer" name="config_notificationServiceArchiveSize" />
<java-symbol type="integer" name="config_previousVibrationsDumpLimit" /> <java-symbol type="integer" name="config_previousVibrationsDumpLimit" />
<java-symbol type="integer" name="config_defaultVibrationAmplitude" /> <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_radioScanningTimeout" />
<java-symbol type="integer" name="config_screenBrightnessSettingMinimum" /> <java-symbol type="integer" name="config_screenBrightnessSettingMinimum" />
<java-symbol type="integer" name="config_screenBrightnessSettingMaximum" /> <java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />

View File

@@ -16,6 +16,7 @@
package com.android.server.vibrator; package com.android.server.vibrator;
import android.content.Context;
import android.os.VibrationEffect; import android.os.VibrationEffect;
import android.os.VibratorInfo; import android.os.VibratorInfo;
@@ -26,17 +27,16 @@ import java.util.List;
final class DeviceVibrationEffectAdapter final class DeviceVibrationEffectAdapter
implements VibrationEffectAdapters.EffectAdapter<VibratorInfo> { 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; private final List<VibrationEffectAdapters.SegmentsAdapter<VibratorInfo>> mSegmentAdapters;
DeviceVibrationEffectAdapter() { DeviceVibrationEffectAdapter(Context context) {
mSegmentAdapters = Arrays.asList( mSegmentAdapters = Arrays.asList(
// TODO(b/167947076): add filter that removes unsupported primitives // TODO(b/167947076): add filter that removes unsupported primitives
// TODO(b/167947076): add filter that replaces unsupported prebaked with fallback // TODO(b/167947076): add filter that replaces unsupported prebaked with fallback
new RampToStepAdapter(RAMP_STEP_DURATION_MILLIS), new RampToStepAdapter(context.getResources().getInteger(
new StepToRampAdapter(), com.android.internal.R.integer.config_vibrationWaveformRampStepDuration)),
new StepToRampAdapter(context.getResources().getInteger(
com.android.internal.R.integer.config_vibrationWaveformRampDownDuration)),
new ClippingAmplitudeAndFrequencyAdapter() new ClippingAmplitudeAndFrequencyAdapter()
); );
} }

View File

@@ -29,7 +29,7 @@ import java.util.List;
/** /**
* Adapter that converts ramp segments that to a sequence of fixed step segments. * 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> { final class RampToStepAdapter implements VibrationEffectAdapters.SegmentsAdapter<VibratorInfo> {

View File

@@ -27,39 +27,221 @@ import java.util.List;
/** /**
* Adapter that converts step segments that should be handled as PWLEs to ramp segments. * 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> { final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter<VibratorInfo> {
private final int mRampDownDuration;
StepToRampAdapter(int rampDownDuration) {
mRampDownDuration = rampDownDuration;
}
@Override @Override
public int apply(List<VibrationEffectSegment> segments, int repeatIndex, public int apply(List<VibrationEffectSegment> segments, int repeatIndex,
VibratorInfo info) { VibratorInfo info) {
if (!info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) { 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; 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(); 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. // Convert steps that require frequency control to ramps.
for (int i = 0; i < segmentCount; i++) { for (int i = 0; i < segmentCount; i++) {
VibrationEffectSegment segment = segments.get(i); VibrationEffectSegment segment = segments.get(i);
if ((segment instanceof StepSegment) if (isStep(segment) && ((StepSegment) segment).getFrequency() != 0) {
&& ((StepSegment) segment).getFrequency() != 0) {
segments.set(i, apply((StepSegment) segment)); segments.set(i, apply((StepSegment) segment));
} }
} }
// Convert steps that are next to ramps to also become ramps, so they can be composed // Convert steps that are next to ramps to also become ramps, so they can be composed
// together in the same PWLE waveform. // 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) { 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))); 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; return repeatIndex;
} }
private RampSegment apply(StepSegment segment) { 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 static RampSegment apply(StepSegment segment) {
return new RampSegment(segment.getAmplitude(), segment.getAmplitude(), return new RampSegment(segment.getAmplitude(), segment.getAmplitude(),
segment.getFrequency(), segment.getFrequency(), (int) segment.getDuration()); 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;
}
} }

View File

@@ -95,8 +95,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
private final WorkSource mWorkSource = new WorkSource(); private final WorkSource mWorkSource = new WorkSource();
private final PowerManager.WakeLock mWakeLock; private final PowerManager.WakeLock mWakeLock;
private final IBatteryStats mBatteryStatsService; private final IBatteryStats mBatteryStatsService;
private final DeviceVibrationEffectAdapter mDeviceEffectAdapter = private final DeviceVibrationEffectAdapter mDeviceEffectAdapter;
new DeviceVibrationEffectAdapter();
private final Vibration mVibration; private final Vibration mVibration;
private final VibrationCallbacks mCallbacks; private final VibrationCallbacks mCallbacks;
private final SparseArray<VibratorController> mVibrators = new SparseArray<>(); private final SparseArray<VibratorController> mVibrators = new SparseArray<>();
@@ -104,10 +103,11 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
private volatile boolean mForceStop; private volatile boolean mForceStop;
VibrationThread(Vibration vib, SparseArray<VibratorController> availableVibrators, VibrationThread(Vibration vib, DeviceVibrationEffectAdapter effectAdapter,
PowerManager.WakeLock wakeLock, IBatteryStats batteryStatsService, SparseArray<VibratorController> availableVibrators, PowerManager.WakeLock wakeLock,
VibrationCallbacks callbacks) { IBatteryStats batteryStatsService, VibrationCallbacks callbacks) {
mVibration = vib; mVibration = vib;
mDeviceEffectAdapter = effectAdapter;
mCallbacks = callbacks; mCallbacks = callbacks;
mWakeLock = wakeLock; mWakeLock = wakeLock;
mWorkSource.set(vib.uid); mWorkSource.set(vib.uid);

View File

@@ -132,6 +132,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
private final VibrationSettings mVibrationSettings; private final VibrationSettings mVibrationSettings;
private final VibrationScaler mVibrationScaler; private final VibrationScaler mVibrationScaler;
private final InputDeviceDelegate mInputDeviceDelegate; private final InputDeviceDelegate mInputDeviceDelegate;
private final DeviceVibrationEffectAdapter mDeviceVibrationEffectAdapter;
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override @Override
@@ -175,6 +176,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
mVibrationSettings = new VibrationSettings(mContext, mHandler); mVibrationSettings = new VibrationSettings(mContext, mHandler);
mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings); mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings);
mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler); mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler);
mDeviceVibrationEffectAdapter = new DeviceVibrationEffectAdapter(mContext);
VibrationCompleteListener listener = new VibrationCompleteListener(this); VibrationCompleteListener listener = new VibrationCompleteListener(this);
mNativeWrapper = injector.getNativeWrapper(); mNativeWrapper = injector.getNativeWrapper();
@@ -512,8 +514,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
return Vibration.Status.FORWARDED_TO_INPUT_DEVICES; return Vibration.Status.FORWARDED_TO_INPUT_DEVICES;
} }
VibrationThread vibThread = new VibrationThread(vib, mVibrators, mWakeLock, VibrationThread vibThread = new VibrationThread(vib, mDeviceVibrationEffectAdapter,
mBatteryStatsService, mVibrationCallbacks); mVibrators, mWakeLock, mBatteryStatsService, mVibrationCallbacks);
if (mCurrentVibration == null) { if (mCurrentVibration == null) {
return startVibrationThreadLocked(vibThread); return startVibrationThreadLocked(vibThread);

View File

@@ -17,6 +17,7 @@
package com.android.server.vibrator; package com.android.server.vibrator;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.hardware.vibrator.IVibrator; import android.hardware.vibrator.IVibrator;
import android.os.VibrationEffect; import android.os.VibrationEffect;
@@ -25,8 +26,11 @@ import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment; import android.os.vibrator.PrimitiveSegment;
import android.os.vibrator.RampSegment; import android.os.vibrator.RampSegment;
import android.os.vibrator.StepSegment; import android.os.vibrator.StepSegment;
import android.os.vibrator.VibrationEffectSegment;
import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -58,7 +62,7 @@ public class DeviceVibrationEffectAdapterTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
mAdapter = new DeviceVibrationEffectAdapter(); mAdapter = new DeviceVibrationEffectAdapter(InstrumentationRegistry.getContext());
} }
@Test @Test
@@ -84,28 +88,19 @@ public class DeviceVibrationEffectAdapterTest {
new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 0.2f, new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 0.2f,
/* startFrequency= */ -4, /* endFrequency= */ 2, /* duration= */ 10), /* startFrequency= */ -4, /* endFrequency= */ 2, /* duration= */ 10),
new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f, 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, new RampSegment(/* startAmplitude= */ 0.65f, /* endAmplitude= */ 0.65f,
/* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 200)), /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 1000)),
/* repeatIndex= */ 3); /* repeatIndex= */ 3);
VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList( VibrationEffect.Composed adaptedEffect = (VibrationEffect.Composed) mAdapter.apply(effect,
new StepSegment(/* amplitude= */ 0, Float.NaN, /* duration= */ 10), createVibratorInfo(EMPTY_FREQUENCY_MAPPING));
new StepSegment(/* amplitude= */ 0.5f, Float.NaN, /* duration= */ 100), assertTrue(adaptedEffect.getSegments().size() > effect.getSegments().size());
// 10ms ramp becomes 2 steps assertTrue(adaptedEffect.getRepeatIndex() >= effect.getRepeatIndex());
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); for (VibrationEffectSegment adaptedSegment : adaptedEffect.getSegments()) {
assertEquals(expected, mAdapter.apply(effect, info)); assertTrue(adaptedSegment instanceof StepSegment);
}
} }
@Test @Test
@@ -135,33 +130,6 @@ public class DeviceVibrationEffectAdapterTest {
assertEquals(expected, mAdapter.apply(effect, info)); 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 @Test
public void testStepAndRampSegments_withEmptyFreqMapping_returnsSameAmplitudesAndZeroFreq() { public void testStepAndRampSegments_withEmptyFreqMapping_returnsSameAmplitudesAndZeroFreq() {
VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -31,6 +31,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.vibrator.Braking; import android.hardware.vibrator.Braking;
import android.hardware.vibrator.IVibrator; import android.hardware.vibrator.IVibrator;
import android.hardware.vibrator.IVibratorManager; import android.hardware.vibrator.IVibratorManager;
@@ -98,13 +99,17 @@ public class VibrationThreadTest {
private IBatteryStats mIBatteryStatsMock; private IBatteryStats mIBatteryStatsMock;
private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>(); private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
private DeviceVibrationEffectAdapter mEffectAdapter;
private PowerManager.WakeLock mWakeLock; private PowerManager.WakeLock mWakeLock;
private TestLooper mTestLooper; private TestLooper mTestLooper;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
mTestLooper = new TestLooper(); 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*"); PowerManager.class).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
mockVibrators(VIBRATOR_ID); mockVibrators(VIBRATOR_ID);
@@ -985,8 +990,8 @@ public class VibrationThreadTest {
} }
private VibrationThread startThreadAndDispatcher(Vibration vib) { private VibrationThread startThreadAndDispatcher(Vibration vib) {
VibrationThread thread = new VibrationThread(vib, createVibratorControllers(), mWakeLock, VibrationThread thread = new VibrationThread(vib, mEffectAdapter,
mIBatteryStatsMock, mThreadCallbacks); createVibratorControllers(), mWakeLock, mIBatteryStatsMock, mThreadCallbacks);
doAnswer(answer -> { doAnswer(answer -> {
thread.vibratorComplete(answer.getArgument(0)); thread.vibratorComplete(answer.getArgument(0));
return null; return null;