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