Merge "Add step down ramp to vibration waveforms" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
50471a76f9
@@ -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