Add step down ramp to vibration waveforms
Update ramp-to-step adapter to also add "step down to zero" segments to off segments in the VibrationEffect waveform. This is the step version of the same behavior implemented for PWLEs supporting "ramp down to zero", and uses the same configured duration. The StepToRampAdapter no longer converts all step waveforms into PWLEs, since now they can also smooth the abrupt amplitude transitions. Bug: 188431691 Test: RampToStepAdapterTest Change-Id: I6e77139f4f21d6c344617bebdb83241b7a951bde
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.server.vibrator;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.VibratorInfo;
|
||||
|
||||
@@ -29,14 +28,13 @@ final class DeviceVibrationEffectAdapter
|
||||
|
||||
private final List<VibrationEffectAdapters.SegmentsAdapter<VibratorInfo>> mSegmentAdapters;
|
||||
|
||||
DeviceVibrationEffectAdapter(Context context) {
|
||||
DeviceVibrationEffectAdapter(VibrationSettings settings) {
|
||||
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(context.getResources().getInteger(
|
||||
com.android.internal.R.integer.config_vibrationWaveformRampStepDuration)),
|
||||
new StepToRampAdapter(context.getResources().getInteger(
|
||||
com.android.internal.R.integer.config_vibrationWaveformRampDownDuration)),
|
||||
new RampToStepAdapter(settings.getRampStepDuration()),
|
||||
new StepToRampAdapter(),
|
||||
new RampDownAdapter(settings.getRampDownDuration(), settings.getRampStepDuration()),
|
||||
new ClippingAmplitudeAndFrequencyAdapter()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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 android.os.VibratorInfo;
|
||||
import android.os.vibrator.RampSegment;
|
||||
import android.os.vibrator.StepSegment;
|
||||
import android.os.vibrator.VibrationEffectSegment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Adapter that applies the ramp down duration config to bring down the vibrator amplitude smoothly.
|
||||
*
|
||||
* <p>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. The
|
||||
* effect overall duration is preserved by this transformation.
|
||||
*
|
||||
* <p>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 or step down will be added to the
|
||||
* transition between ON and OFF. The ramps/steps can be shorter than the configured duration in
|
||||
* order to preserve the waveform timings, but they will still soften the ringing effect.
|
||||
*
|
||||
* <p>If the segment preceding an OFF segment a {@link RampSegment} then a new ramp segment will be
|
||||
* added to bring the amplitude down. If it is a {@link StepSegment} then a sequence of steps will
|
||||
* be used to bring the amplitude down to zero. This ensures that the transition from the last
|
||||
* amplitude to zero will be handled by the same vibrate method.
|
||||
*/
|
||||
final class RampDownAdapter implements VibrationEffectAdapters.SegmentsAdapter<VibratorInfo> {
|
||||
private final int mRampDownDuration;
|
||||
private final int mStepDuration;
|
||||
|
||||
RampDownAdapter(int rampDownDuration, int stepDuration) {
|
||||
mRampDownDuration = rampDownDuration;
|
||||
mStepDuration = stepDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int apply(List<VibrationEffectSegment> segments, int repeatIndex,
|
||||
VibratorInfo info) {
|
||||
if (mRampDownDuration <= 0) {
|
||||
// Nothing to do, no ramp down duration configured.
|
||||
return repeatIndex;
|
||||
}
|
||||
repeatIndex = addRampDownToZeroAmplitudeSegments(segments, repeatIndex);
|
||||
repeatIndex = addRampDownToLoop(segments, repeatIndex);
|
||||
return repeatIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will add ramp or steps down to zero as follows:
|
||||
*
|
||||
* <ol>
|
||||
* <li>Remove the OFF segment that follows a segment of non-zero amplitude;
|
||||
* <li>Add a single {@link RampSegment} or a list of {@link StepSegment} starting at the
|
||||
* previous segment's amplitude and frequency, with min between the configured ramp down
|
||||
* duration or the removed segment's duration;
|
||||
* <li>Add a zero amplitude segment following the steps, if necessary, to fill the remaining
|
||||
* duration;
|
||||
* </ol>
|
||||
*/
|
||||
private int addRampDownToZeroAmplitudeSegments(List<VibrationEffectSegment> segments,
|
||||
int repeatIndex) {
|
||||
int newRepeatIndex = repeatIndex;
|
||||
int newSegmentCount = segments.size();
|
||||
for (int i = 1; i < newSegmentCount; i++) {
|
||||
VibrationEffectSegment previousSegment = segments.get(i - 1);
|
||||
if (!isOffSegment(segments.get(i))
|
||||
|| !endsWithNonZeroAmplitude(previousSegment)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<VibrationEffectSegment> replacementSegments = null;
|
||||
long offDuration = segments.get(i).getDuration();
|
||||
|
||||
if (previousSegment instanceof StepSegment) {
|
||||
float previousAmplitude = ((StepSegment) previousSegment).getAmplitude();
|
||||
float previousFrequency = ((StepSegment) previousSegment).getFrequency();
|
||||
|
||||
replacementSegments =
|
||||
createStepsDown(previousAmplitude, previousFrequency, offDuration);
|
||||
} else if (previousSegment instanceof RampSegment) {
|
||||
float previousAmplitude = ((RampSegment) previousSegment).getEndAmplitude();
|
||||
float previousFrequency = ((RampSegment) previousSegment).getEndFrequency();
|
||||
|
||||
if (offDuration <= mRampDownDuration) {
|
||||
// Replace the zero amplitude segment with a ramp down of same duration, to
|
||||
// preserve waveform timings and still soften the transition to zero.
|
||||
replacementSegments = Arrays.asList(
|
||||
createRampDown(previousAmplitude, previousFrequency, offDuration));
|
||||
} else {
|
||||
// Replace the zero amplitude segment with a ramp down of configured duration
|
||||
// followed by a shorter off segment.
|
||||
replacementSegments = Arrays.asList(
|
||||
createRampDown(previousAmplitude, previousFrequency, mRampDownDuration),
|
||||
createRampDown(0, previousFrequency, offDuration - mRampDownDuration));
|
||||
}
|
||||
}
|
||||
|
||||
if (replacementSegments != null) {
|
||||
int segmentsAdded = replacementSegments.size() - 1;
|
||||
|
||||
segments.remove(i);
|
||||
segments.addAll(i, replacementSegments);
|
||||
if (repeatIndex > i) {
|
||||
newRepeatIndex += segmentsAdded;
|
||||
}
|
||||
i += segmentsAdded;
|
||||
newSegmentCount += segmentsAdded;
|
||||
}
|
||||
}
|
||||
return newRepeatIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will ramps down 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 has zero amplitude.
|
||||
* The update is described as:
|
||||
*
|
||||
* <ol>
|
||||
* <li>Add a ramp or sequence of steps 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) {
|
||||
// Nothing to do, no ramp down duration configured or effect is not repeating.
|
||||
return repeatIndex;
|
||||
}
|
||||
|
||||
int segmentCount = segments.size();
|
||||
if (!endsWithNonZeroAmplitude(segments.get(segmentCount - 1))
|
||||
|| !isOffSegment(segments.get(repeatIndex))) {
|
||||
// Nothing to do, not going back from a positive amplitude to a off segment.
|
||||
return repeatIndex;
|
||||
}
|
||||
|
||||
VibrationEffectSegment lastSegment = segments.get(segmentCount - 1);
|
||||
VibrationEffectSegment offSegment = segments.get(repeatIndex);
|
||||
long offDuration = offSegment.getDuration();
|
||||
|
||||
if (offDuration > mRampDownDuration) {
|
||||
// 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.set(repeatIndex, updateDuration(offSegment, offDuration - mRampDownDuration));
|
||||
segments.add(repeatIndex, updateDuration(offSegment, mRampDownDuration));
|
||||
}
|
||||
|
||||
// Skip the zero amplitude segment and append ramp/steps down at the end.
|
||||
repeatIndex++;
|
||||
if (lastSegment instanceof StepSegment) {
|
||||
float previousAmplitude = ((StepSegment) lastSegment).getAmplitude();
|
||||
float previousFrequency = ((StepSegment) lastSegment).getFrequency();
|
||||
segments.addAll(createStepsDown(previousAmplitude, previousFrequency,
|
||||
Math.min(offDuration, mRampDownDuration)));
|
||||
} else if (lastSegment instanceof RampSegment) {
|
||||
float previousAmplitude = ((RampSegment) lastSegment).getEndAmplitude();
|
||||
float previousFrequency = ((RampSegment) lastSegment).getEndFrequency();
|
||||
segments.add(createRampDown(previousAmplitude, previousFrequency,
|
||||
Math.min(offDuration, mRampDownDuration)));
|
||||
}
|
||||
|
||||
return repeatIndex;
|
||||
}
|
||||
|
||||
private List<VibrationEffectSegment> createStepsDown(float amplitude, float frequency,
|
||||
long duration) {
|
||||
// Step down for at most the configured ramp duration.
|
||||
int stepCount = (int) Math.min(duration, mRampDownDuration) / mStepDuration;
|
||||
float amplitudeStep = amplitude / stepCount;
|
||||
List<VibrationEffectSegment> steps = new ArrayList<>();
|
||||
for (int i = 1; i < stepCount; i++) {
|
||||
steps.add(new StepSegment(amplitude - i * amplitudeStep, frequency, mStepDuration));
|
||||
}
|
||||
int remainingDuration = (int) duration - mStepDuration * (stepCount - 1);
|
||||
steps.add(new StepSegment(0, frequency, remainingDuration));
|
||||
return steps;
|
||||
}
|
||||
|
||||
private static RampSegment createRampDown(float amplitude, float frequency, long duration) {
|
||||
return new RampSegment(amplitude, /* endAmplitude= */ 0, frequency, frequency,
|
||||
(int) duration);
|
||||
}
|
||||
|
||||
private static VibrationEffectSegment updateDuration(VibrationEffectSegment segment,
|
||||
long newDuration) {
|
||||
if (segment instanceof RampSegment) {
|
||||
RampSegment ramp = (RampSegment) segment;
|
||||
return new RampSegment(ramp.getStartAmplitude(), ramp.getEndAmplitude(),
|
||||
ramp.getStartFrequency(), ramp.getEndFrequency(), (int) newDuration);
|
||||
} else if (segment instanceof StepSegment) {
|
||||
StepSegment step = (StepSegment) segment;
|
||||
return new StepSegment(step.getAmplitude(), step.getFrequency(), (int) newDuration);
|
||||
}
|
||||
return segment;
|
||||
}
|
||||
|
||||
/** Returns true if the segment is a ramp or a step that starts and ends at zero amplitude. */
|
||||
private static boolean isOffSegment(VibrationEffectSegment segment) {
|
||||
if (segment instanceof StepSegment) {
|
||||
StepSegment ramp = (StepSegment) segment;
|
||||
return ramp.getAmplitude() == 0;
|
||||
} else if (segment instanceof RampSegment) {
|
||||
RampSegment ramp = (RampSegment) segment;
|
||||
return ramp.getStartAmplitude() == 0 && ramp.getEndAmplitude() == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns true if the segment is a ramp or a step that ends at a non-zero amplitude. */
|
||||
private static boolean endsWithNonZeroAmplitude(VibrationEffectSegment segment) {
|
||||
if (segment instanceof StepSegment) {
|
||||
return ((StepSegment) segment).getAmplitude() != 0;
|
||||
} else if (segment instanceof RampSegment) {
|
||||
return ((RampSegment) segment).getEndAmplitude() != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -31,25 +31,9 @@ import java.util.List;
|
||||
* <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) {
|
||||
@@ -58,28 +42,17 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter
|
||||
return repeatIndex;
|
||||
}
|
||||
convertStepsToRamps(segments);
|
||||
int newRepeatIndex = addRampDownToZeroAmplitudeSegments(segments, repeatIndex);
|
||||
newRepeatIndex = addRampDownToLoop(segments, newRepeatIndex);
|
||||
newRepeatIndex = splitLongRampSegments(info, segments, newRepeatIndex);
|
||||
return newRepeatIndex;
|
||||
repeatIndex = splitLongRampSegments(info, segments, repeatIndex);
|
||||
return repeatIndex;
|
||||
}
|
||||
|
||||
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 (isStep(segment) && ((StepSegment) segment).getFrequency() != 0) {
|
||||
segments.set(i, apply((StepSegment) segment));
|
||||
segments.set(i, convertStepToRamp((StepSegment) segment));
|
||||
}
|
||||
}
|
||||
// Convert steps that are next to ramps to also become ramps, so they can be composed
|
||||
@@ -87,131 +60,15 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter
|
||||
for (int i = 0; i < segmentCount; i++) {
|
||||
if (segments.get(i) instanceof RampSegment) {
|
||||
for (int j = i - 1; j >= 0 && isStep(segments.get(j)); j--) {
|
||||
segments.set(j, apply((StepSegment) segments.get(j)));
|
||||
segments.set(j, convertStepToRamp((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, convertStepToRamp((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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split {@link RampSegment} entries that have duration longer than {@link
|
||||
* VibratorInfo#getPwlePrimitiveDurationMax()}.
|
||||
@@ -247,7 +104,7 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter
|
||||
return repeatIndex;
|
||||
}
|
||||
|
||||
private static RampSegment apply(StepSegment segment) {
|
||||
private static RampSegment convertStepToRamp(StepSegment segment) {
|
||||
return new RampSegment(segment.getAmplitude(), segment.getAmplitude(),
|
||||
segment.getFrequency(), segment.getFrequency(), (int) segment.getDuration());
|
||||
}
|
||||
@@ -276,36 +133,10 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter
|
||||
return ramps;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static float interpolateAmplitude(RampSegment ramp, long duration) {
|
||||
return interpolate(ramp.getStartAmplitude(), ramp.getEndAmplitude(), duration,
|
||||
ramp.getDuration());
|
||||
|
||||
@@ -67,11 +67,13 @@ final class VibrationSettings {
|
||||
@VisibleForTesting
|
||||
final UserObserver mUserReceiver;
|
||||
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final List<OnVibratorSettingsChanged> mListeners = new ArrayList<>();
|
||||
private final SparseArray<VibrationEffect> mFallbackEffects;
|
||||
|
||||
private final int mRampStepDuration;
|
||||
private final int mRampDownDuration;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
private Vibrator mVibrator;
|
||||
@@ -102,6 +104,12 @@ final class VibrationSettings {
|
||||
mUidObserver = new UidObserver();
|
||||
mUserReceiver = new UserObserver();
|
||||
|
||||
// TODO(b/191150049): move these to vibrator static config file
|
||||
mRampStepDuration = context.getResources().getInteger(
|
||||
com.android.internal.R.integer.config_vibrationWaveformRampStepDuration);
|
||||
mRampDownDuration = context.getResources().getInteger(
|
||||
com.android.internal.R.integer.config_vibrationWaveformRampDownDuration);
|
||||
|
||||
VibrationEffect clickEffect = createEffectFromResource(
|
||||
com.android.internal.R.array.config_virtualKeyVibePattern);
|
||||
VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
|
||||
@@ -192,6 +200,23 @@ final class VibrationSettings {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The duration, in milliseconds, that should be applied to convert vibration effect's
|
||||
* {@link android.os.vibrator.RampSegment} to a {@link android.os.vibrator.StepSegment} on
|
||||
* devices without PWLE support.
|
||||
*/
|
||||
public int getRampStepDuration() {
|
||||
return mRampStepDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* The duration, in milliseconds, that should be applied to the ramp to turn off the vibrator
|
||||
* when a vibration is cancelled or finished at non-zero amplitude.
|
||||
*/
|
||||
public int getRampDownDuration() {
|
||||
return mRampDownDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return default vibration intensity for given usage.
|
||||
*
|
||||
@@ -354,6 +379,8 @@ final class VibrationSettings {
|
||||
+ ", mZenMode=" + Settings.Global.zenModeToString(mZenMode)
|
||||
+ ", mProcStatesCache=" + mUidObserver.mProcStatesCache
|
||||
+ ", mHapticChannelMaxVibrationAmplitude=" + getHapticChannelMaxVibrationAmplitude()
|
||||
+ ", mRampStepDuration=" + mRampStepDuration
|
||||
+ ", mRampDownDuration=" + mRampDownDuration
|
||||
+ ", mHapticFeedbackIntensity="
|
||||
+ intensityToString(getCurrentIntensity(VibrationAttributes.USAGE_TOUCH))
|
||||
+ ", mHapticFeedbackDefaultIntensity="
|
||||
|
||||
@@ -176,7 +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);
|
||||
mDeviceVibrationEffectAdapter = new DeviceVibrationEffectAdapter(mVibrationSettings);
|
||||
|
||||
VibrationCompleteListener listener = new VibrationCompleteListener(this);
|
||||
mNativeWrapper = injector.getNativeWrapper();
|
||||
|
||||
@@ -20,8 +20,10 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.hardware.vibrator.IVibrator;
|
||||
import android.os.Handler;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.VibratorInfo;
|
||||
import android.os.test.TestLooper;
|
||||
import android.os.vibrator.PrebakedSegment;
|
||||
import android.os.vibrator.PrimitiveSegment;
|
||||
import android.os.vibrator.RampSegment;
|
||||
@@ -62,7 +64,9 @@ public class DeviceVibrationEffectAdapterTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mAdapter = new DeviceVibrationEffectAdapter(InstrumentationRegistry.getContext());
|
||||
VibrationSettings vibrationSettings = new VibrationSettings(
|
||||
InstrumentationRegistry.getContext(), new Handler(new TestLooper().getLooper()));
|
||||
mAdapter = new DeviceVibrationEffectAdapter(vibrationSettings);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* 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.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;
|
||||
|
||||
/**
|
||||
* Tests for {@link RampDownAdapter}.
|
||||
*
|
||||
* Build/Install/Run:
|
||||
* atest FrameworksServicesTests:RampDownAdapterTest
|
||||
*/
|
||||
@Presubmit
|
||||
public class RampDownAdapterTest {
|
||||
private static final int TEST_RAMP_DOWN_DURATION = 20;
|
||||
private static final int TEST_STEP_DURATION = 5;
|
||||
private static final VibratorInfo TEST_VIBRATOR_INFO = new VibratorInfo.Builder(0).build();
|
||||
|
||||
private RampDownAdapter mAdapter;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mAdapter = new RampDownAdapter(TEST_RAMP_DOWN_DURATION, TEST_STEP_DURATION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrebakedAndPrimitiveSegments_keepsListUnchanged() {
|
||||
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
|
||||
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, TEST_VIBRATOR_INFO));
|
||||
assertEquals(1, mAdapter.apply(segments, 1, TEST_VIBRATOR_INFO));
|
||||
|
||||
assertEquals(originalSegments, segments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRampAndStepSegments_withNoOffSegment_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);
|
||||
|
||||
assertEquals(-1, mAdapter.apply(segments, -1, TEST_VIBRATOR_INFO));
|
||||
assertEquals(0, mAdapter.apply(segments, 0, TEST_VIBRATOR_INFO));
|
||||
|
||||
assertEquals(originalSegments, segments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRampAndStepSegments_withNoRampDownDuration_keepsOriginalSteps() {
|
||||
mAdapter = new RampDownAdapter(/* rampDownDuration= */ 0, TEST_STEP_DURATION);
|
||||
|
||||
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
|
||||
new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
|
||||
new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 100),
|
||||
new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f,
|
||||
/* startFrequency= */ 10, /* endFrequency= */ -5, /* duration= */ 20),
|
||||
new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0,
|
||||
/* startFrequency= */ 0, /* endFrequency= */ 0, /* duration= */ 50)));
|
||||
List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
|
||||
|
||||
assertEquals(-1, mAdapter.apply(segments, -1, TEST_VIBRATOR_INFO));
|
||||
assertEquals(2, mAdapter.apply(segments, 2, TEST_VIBRATOR_INFO));
|
||||
assertEquals(originalSegments, segments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStepSegments_withShortZeroSegment_replaceWithStepsDown() {
|
||||
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
|
||||
new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
|
||||
new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 10),
|
||||
new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 0, /* duration= */ 100)));
|
||||
List<VibrationEffectSegment> expectedSegments = Arrays.asList(
|
||||
new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
|
||||
new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 5),
|
||||
new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 5),
|
||||
new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 0, /* duration= */ 100));
|
||||
|
||||
assertEquals(1, mAdapter.apply(segments, 1, TEST_VIBRATOR_INFO));
|
||||
|
||||
assertEquals(expectedSegments, segments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStepSegments_withLongZeroSegment_replaceWithStepsDown() {
|
||||
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
|
||||
new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
|
||||
new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0,
|
||||
/* startFrequency= */ 0, /* endFrequency= */ 0, /* duration= */ 50),
|
||||
new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 0, /* duration= */ 100)));
|
||||
List<VibrationEffectSegment> expectedSegments = Arrays.asList(
|
||||
new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 10),
|
||||
new StepSegment(/* amplitude= */ 0.75f, /* frequency= */ 0, /* duration= */ 5),
|
||||
new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 5),
|
||||
new StepSegment(/* amplitude= */ 0.25f, /* frequency= */ 0, /* duration= */ 5),
|
||||
new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 35),
|
||||
new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 0, /* duration= */ 100));
|
||||
|
||||
// Repeat index fixed after intermediate steps added
|
||||
assertEquals(5, mAdapter.apply(segments, 2, TEST_VIBRATOR_INFO));
|
||||
|
||||
assertEquals(expectedSegments, segments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStepSegments_withRepeatToNonZeroSegment_keepsOriginalSteps() {
|
||||
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
|
||||
new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 0, /* duration= */ 10),
|
||||
new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100)));
|
||||
List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
|
||||
|
||||
assertEquals(0, mAdapter.apply(segments, 0, TEST_VIBRATOR_INFO));
|
||||
|
||||
assertEquals(originalSegments, segments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStepSegments_withRepeatToShortZeroSegment_skipAndAppendRampDown() {
|
||||
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
|
||||
new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0,
|
||||
/* startFrequency= */ 0, /* endFrequency= */ 0, /* duration= */ 10),
|
||||
new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 30)));
|
||||
List<VibrationEffectSegment> expectedSegments = Arrays.asList(
|
||||
new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0,
|
||||
/* startFrequency= */ 0, /* endFrequency= */ 0, /* duration= */ 10),
|
||||
new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 30),
|
||||
new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 5),
|
||||
new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 5));
|
||||
|
||||
// Shift repeat index to the right to use append instead of zero segment.
|
||||
assertEquals(1, mAdapter.apply(segments, 0, TEST_VIBRATOR_INFO));
|
||||
|
||||
assertEquals(expectedSegments, segments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStepSegments_withRepeatToLongZeroSegment_splitAndAppendRampDown() {
|
||||
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
|
||||
new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 120),
|
||||
new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 30)));
|
||||
List<VibrationEffectSegment> expectedSegments = Arrays.asList(
|
||||
// Split long zero segment to skip part of it.
|
||||
new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 20),
|
||||
new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 100),
|
||||
new StepSegment(/* amplitude= */ 1, /* frequency= */ 0, /* duration= */ 30),
|
||||
new StepSegment(/* amplitude= */ 0.75f, /* frequency= */ 0, /* duration= */ 5),
|
||||
new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 5),
|
||||
new StepSegment(/* amplitude= */ 0.25f, /* frequency= */ 0, /* duration= */ 5),
|
||||
new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 5));
|
||||
|
||||
// Shift repeat index to the right to use append with part of the zero segment.
|
||||
assertEquals(1, mAdapter.apply(segments, 0, TEST_VIBRATOR_INFO));
|
||||
|
||||
assertEquals(expectedSegments, segments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRampSegments_withShortZeroSegment_replaceWithRampDown() {
|
||||
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
|
||||
new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
|
||||
/* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10),
|
||||
new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0,
|
||||
/* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 20),
|
||||
new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
|
||||
/* startFrequency= */ 1, /* endFrequency= */ 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));
|
||||
|
||||
assertEquals(2, mAdapter.apply(segments, 2, TEST_VIBRATOR_INFO));
|
||||
|
||||
assertEquals(expectedSegments, segments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRampSegments_withLongZeroSegment_splitAndAddRampDown() {
|
||||
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
|
||||
new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
|
||||
/* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10),
|
||||
new StepSegment(/* amplitude= */ 0, /* frequency= */ 0, /* duration= */ 150),
|
||||
new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
|
||||
/* startFrequency= */ 1, /* endFrequency= */ 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= */ 0, /* endAmplitude= */ 0,
|
||||
/* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 130),
|
||||
new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 1,
|
||||
/* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 30));
|
||||
|
||||
// Repeat index fixed after intermediate steps added
|
||||
assertEquals(3, mAdapter.apply(segments, 2, TEST_VIBRATOR_INFO));
|
||||
|
||||
assertEquals(expectedSegments, segments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRampSegments_withRepeatToNonZeroSegment_keepsOriginalSteps() {
|
||||
List<VibrationEffectSegment> segments = new ArrayList<>(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)));
|
||||
List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
|
||||
|
||||
assertEquals(0, mAdapter.apply(segments, 0, TEST_VIBRATOR_INFO));
|
||||
|
||||
assertEquals(originalSegments, segments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRampSegments_withRepeatToShortZeroSegment_skipAndAppendRampDown() {
|
||||
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
|
||||
new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 20),
|
||||
new RampSegment(/* startAmplitude= */ 0, /* endAmplitude*/ 1,
|
||||
/* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 20)));
|
||||
List<VibrationEffectSegment> expectedSegments = Arrays.asList(
|
||||
new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 20),
|
||||
new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 1,
|
||||
/* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 20),
|
||||
new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 0,
|
||||
/* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 20));
|
||||
|
||||
// Shift repeat index to the right to use append instead of zero segment.
|
||||
assertEquals(1, mAdapter.apply(segments, 0, TEST_VIBRATOR_INFO));
|
||||
|
||||
assertEquals(expectedSegments, segments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRampSegments_withRepeatToLongZeroSegment_splitAndAppendRampDown() {
|
||||
List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
|
||||
new RampSegment(/* startAmplitude= */ 0, /* endAmplitude*/ 0,
|
||||
/* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 70),
|
||||
new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 1,
|
||||
/* startFrequency= */ 1, /* endFrequency= */ 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= */ 20),
|
||||
new RampSegment(/* startAmplitude= */ 0, /* endAmplitude*/ 0,
|
||||
/* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 50),
|
||||
new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 1,
|
||||
/* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 30),
|
||||
new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 0,
|
||||
/* startFrequency= */ 1, /* endFrequency= */ 1, /* duration= */ 20));
|
||||
|
||||
// Shift repeat index to the right to use append with part of the zero segment.
|
||||
assertEquals(1, mAdapter.apply(segments, 0, TEST_VIBRATOR_INFO));
|
||||
|
||||
assertEquals(expectedSegments, segments);
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class StepToRampAdapterTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mAdapter = new StepToRampAdapter(/* rampDownDuration= */ 0);
|
||||
mAdapter = new StepToRampAdapter();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -101,8 +101,6 @@ public class StepToRampAdapterTest {
|
||||
|
||||
@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,
|
||||
@@ -182,160 +180,6 @@ public class StepToRampAdapterTest {
|
||||
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))
|
||||
|
||||
@@ -36,6 +36,7 @@ import android.hardware.vibrator.Braking;
|
||||
import android.hardware.vibrator.IVibrator;
|
||||
import android.hardware.vibrator.IVibratorManager;
|
||||
import android.os.CombinedVibration;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Process;
|
||||
@@ -108,7 +109,9 @@ public class VibrationThreadTest {
|
||||
mTestLooper = new TestLooper();
|
||||
|
||||
Context context = InstrumentationRegistry.getContext();
|
||||
mEffectAdapter = new DeviceVibrationEffectAdapter(context);
|
||||
VibrationSettings vibrationSettings = new VibrationSettings(context,
|
||||
new Handler(mTestLooper.getLooper()));
|
||||
mEffectAdapter = new DeviceVibrationEffectAdapter(vibrationSettings);
|
||||
mWakeLock = context.getSystemService(
|
||||
PowerManager.class).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user