Merge "Split vibration effect adapters into separate files" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
b2198d3a3d
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 android.util.MathUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Adapter that clips frequency values to {@link VibratorInfo#getFrequencyRange()} and
|
||||
* amplitude values to respective {@link VibratorInfo#getMaxAmplitude}.
|
||||
*
|
||||
* <p>Devices with no frequency control will collapse all frequencies to zero and leave
|
||||
* amplitudes unchanged.
|
||||
*
|
||||
* <p>The frequency value returned in segments will be absolute, converted with
|
||||
* {@link VibratorInfo#getAbsoluteFrequency(float)}.
|
||||
*/
|
||||
final class ClippingAmplitudeAndFrequencyAdapter
|
||||
implements VibrationEffectAdapters.SegmentsAdapter<VibratorInfo> {
|
||||
|
||||
@Override
|
||||
public int apply(List<VibrationEffectSegment> segments, int repeatIndex, VibratorInfo info) {
|
||||
int segmentCount = segments.size();
|
||||
for (int i = 0; i < segmentCount; i++) {
|
||||
VibrationEffectSegment segment = segments.get(i);
|
||||
if (segment instanceof StepSegment) {
|
||||
segments.set(i, apply((StepSegment) segment, info));
|
||||
} else if (segment instanceof RampSegment) {
|
||||
segments.set(i, apply((RampSegment) segment, info));
|
||||
}
|
||||
}
|
||||
return repeatIndex;
|
||||
}
|
||||
|
||||
private StepSegment apply(StepSegment segment, VibratorInfo info) {
|
||||
float clampedFrequency = clampFrequency(info, segment.getFrequency());
|
||||
return new StepSegment(
|
||||
clampAmplitude(info, clampedFrequency, segment.getAmplitude()),
|
||||
info.getAbsoluteFrequency(clampedFrequency),
|
||||
(int) segment.getDuration());
|
||||
}
|
||||
|
||||
private RampSegment apply(RampSegment segment, VibratorInfo info) {
|
||||
float clampedStartFrequency = clampFrequency(info, segment.getStartFrequency());
|
||||
float clampedEndFrequency = clampFrequency(info, segment.getEndFrequency());
|
||||
return new RampSegment(
|
||||
clampAmplitude(info, clampedStartFrequency, segment.getStartAmplitude()),
|
||||
clampAmplitude(info, clampedEndFrequency, segment.getEndAmplitude()),
|
||||
info.getAbsoluteFrequency(clampedStartFrequency),
|
||||
info.getAbsoluteFrequency(clampedEndFrequency),
|
||||
(int) segment.getDuration());
|
||||
}
|
||||
|
||||
private float clampFrequency(VibratorInfo info, float frequency) {
|
||||
return info.getFrequencyRange().clamp(frequency);
|
||||
}
|
||||
|
||||
private float clampAmplitude(VibratorInfo info, float frequency, float amplitude) {
|
||||
return MathUtils.min(amplitude, info.getMaxAmplitude(frequency));
|
||||
}
|
||||
}
|
||||
@@ -16,231 +16,33 @@
|
||||
|
||||
package com.android.server.vibrator;
|
||||
|
||||
import android.hardware.vibrator.IVibrator;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.VibratorInfo;
|
||||
import android.os.vibrator.RampSegment;
|
||||
import android.os.vibrator.StepSegment;
|
||||
import android.os.vibrator.VibrationEffectSegment;
|
||||
import android.util.MathUtils;
|
||||
import android.util.Range;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/** Adapts a {@link VibrationEffect} to a specific device, taking into account its capabilities. */
|
||||
final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<VibratorInfo> {
|
||||
final class DeviceVibrationEffectAdapter
|
||||
implements VibrationEffectAdapters.EffectAdapter<VibratorInfo> {
|
||||
|
||||
/** Duration of each step created to simulate a ramp segment. */
|
||||
private static final int RAMP_STEP_DURATION_MILLIS = 5;
|
||||
|
||||
/** Adapts a sequence of {@link VibrationEffectSegment} to device's capabilities. */
|
||||
interface SegmentsAdapter {
|
||||
|
||||
/**
|
||||
* Modifies the given segments list by adding/removing segments to it based on the
|
||||
* device capabilities specified by given {@link VibratorInfo}.
|
||||
*
|
||||
* @param segments List of {@link VibrationEffectSegment} to be modified.
|
||||
* @param repeatIndex Repeat index of the vibration with given segment list.
|
||||
* @param info The device vibrator info that the segments must be adapted to.
|
||||
* @return The new repeat index to be used for the modified list.
|
||||
*/
|
||||
int apply(List<VibrationEffectSegment> segments, int repeatIndex, VibratorInfo info);
|
||||
}
|
||||
|
||||
private final SegmentsAdapter mAmplitudeFrequencyAdapter;
|
||||
private final SegmentsAdapter mStepToRampAdapter;
|
||||
private final SegmentsAdapter mRampToStepsAdapter;
|
||||
private final List<VibrationEffectAdapters.SegmentsAdapter<VibratorInfo>> mSegmentAdapters;
|
||||
|
||||
DeviceVibrationEffectAdapter() {
|
||||
this(new ClippingAmplitudeFrequencyAdapter());
|
||||
}
|
||||
|
||||
DeviceVibrationEffectAdapter(SegmentsAdapter amplitudeFrequencyAdapter) {
|
||||
mAmplitudeFrequencyAdapter = amplitudeFrequencyAdapter;
|
||||
mStepToRampAdapter = new StepToRampAdapter();
|
||||
mRampToStepsAdapter = new RampToStepsAdapter(RAMP_STEP_DURATION_MILLIS);
|
||||
mSegmentAdapters = Arrays.asList(
|
||||
// TODO(b/167947076): add filter that removes unsupported primitives
|
||||
// TODO(b/167947076): add filter that replaces unsupported prebaked with fallback
|
||||
new RampToStepAdapter(RAMP_STEP_DURATION_MILLIS),
|
||||
new StepToRampAdapter(),
|
||||
new ClippingAmplitudeAndFrequencyAdapter()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VibrationEffect apply(VibrationEffect effect, VibratorInfo info) {
|
||||
if (!(effect instanceof VibrationEffect.Composed)) {
|
||||
return effect;
|
||||
}
|
||||
|
||||
VibrationEffect.Composed composed = (VibrationEffect.Composed) effect;
|
||||
List<VibrationEffectSegment> newSegments = new ArrayList<>(composed.getSegments());
|
||||
int newRepeatIndex = composed.getRepeatIndex();
|
||||
|
||||
// Replace ramps with a sequence of fixed steps, or no-op if PWLE capability present.
|
||||
newRepeatIndex = mRampToStepsAdapter.apply(newSegments, newRepeatIndex, info);
|
||||
|
||||
// Replace steps that should be handled by PWLE to ramps, or no-op if capability missing.
|
||||
// This should be done before frequency is converted from relative to absolute values.
|
||||
newRepeatIndex = mStepToRampAdapter.apply(newSegments, newRepeatIndex, info);
|
||||
|
||||
// Adapt amplitude and frequency values to device supported ones, converting frequency
|
||||
// to absolute values in Hertz.
|
||||
newRepeatIndex = mAmplitudeFrequencyAdapter.apply(newSegments, newRepeatIndex, info);
|
||||
|
||||
// TODO(b/167947076): add filter that removes unsupported primitives
|
||||
// TODO(b/167947076): add filter that replaces unsupported prebaked with fallback
|
||||
|
||||
return new VibrationEffect.Composed(newSegments, newRepeatIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter that converts step segments that should be handled as PWLEs to ramp segments.
|
||||
*
|
||||
* <p>This leaves the list unchanged if the device do not have compose PWLE capability.
|
||||
*/
|
||||
private static final class StepToRampAdapter implements SegmentsAdapter {
|
||||
@Override
|
||||
public int apply(List<VibrationEffectSegment> segments, int repeatIndex,
|
||||
VibratorInfo info) {
|
||||
if (!info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
|
||||
// The vibrator do not have PWLE capability, so keep the segments unchanged.
|
||||
return repeatIndex;
|
||||
}
|
||||
int segmentCount = segments.size();
|
||||
// Convert steps that require frequency control to ramps.
|
||||
for (int i = 0; i < segmentCount; i++) {
|
||||
VibrationEffectSegment segment = segments.get(i);
|
||||
if ((segment instanceof StepSegment)
|
||||
&& ((StepSegment) segment).getFrequency() != 0) {
|
||||
segments.set(i, apply((StepSegment) segment));
|
||||
}
|
||||
}
|
||||
// Convert steps that are next to ramps to also become ramps, so they can be composed
|
||||
// together in the same PWLE waveform.
|
||||
for (int i = 1; i < segmentCount; i++) {
|
||||
if (segments.get(i) instanceof RampSegment) {
|
||||
for (int j = i - 1; j >= 0 && (segments.get(j) instanceof StepSegment); j--) {
|
||||
segments.set(j, apply((StepSegment) segments.get(j)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return repeatIndex;
|
||||
}
|
||||
|
||||
private RampSegment apply(StepSegment segment) {
|
||||
return new RampSegment(segment.getAmplitude(), segment.getAmplitude(),
|
||||
segment.getFrequency(), segment.getFrequency(), (int) segment.getDuration());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter that converts ramp segments that to a sequence of fixed step segments.
|
||||
*
|
||||
* <p>This leaves the list unchanged if the device have compose PWLE capability.
|
||||
*/
|
||||
private static final class RampToStepsAdapter implements SegmentsAdapter {
|
||||
private final int mStepDuration;
|
||||
|
||||
RampToStepsAdapter(int stepDuration) {
|
||||
mStepDuration = stepDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int apply(List<VibrationEffectSegment> segments, int repeatIndex,
|
||||
VibratorInfo info) {
|
||||
if (info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
|
||||
// The vibrator have PWLE capability, so keep the segments unchanged.
|
||||
return repeatIndex;
|
||||
}
|
||||
int segmentCount = segments.size();
|
||||
for (int i = 0; i < segmentCount; i++) {
|
||||
VibrationEffectSegment segment = segments.get(i);
|
||||
if (!(segment instanceof RampSegment)) {
|
||||
continue;
|
||||
}
|
||||
List<StepSegment> steps = apply((RampSegment) segment);
|
||||
segments.remove(i);
|
||||
segments.addAll(i, steps);
|
||||
int addedSegments = steps.size() - 1;
|
||||
if (repeatIndex > i) {
|
||||
repeatIndex += addedSegments;
|
||||
}
|
||||
i += addedSegments;
|
||||
segmentCount += addedSegments;
|
||||
}
|
||||
return repeatIndex;
|
||||
}
|
||||
|
||||
private List<StepSegment> apply(RampSegment ramp) {
|
||||
if (Float.compare(ramp.getStartAmplitude(), ramp.getEndAmplitude()) == 0) {
|
||||
// Amplitude is the same, so return a single step to simulate this ramp.
|
||||
return Arrays.asList(
|
||||
new StepSegment(ramp.getStartAmplitude(), ramp.getStartFrequency(),
|
||||
(int) ramp.getDuration()));
|
||||
}
|
||||
|
||||
List<StepSegment> steps = new ArrayList<>();
|
||||
int stepCount = (int) (ramp.getDuration() + mStepDuration - 1) / mStepDuration;
|
||||
for (int i = 0; i < stepCount - 1; i++) {
|
||||
float pos = (float) i / stepCount;
|
||||
steps.add(new StepSegment(
|
||||
interpolate(ramp.getStartAmplitude(), ramp.getEndAmplitude(), pos),
|
||||
interpolate(ramp.getStartFrequency(), ramp.getEndFrequency(), pos),
|
||||
mStepDuration));
|
||||
}
|
||||
int duration = (int) ramp.getDuration() - mStepDuration * (stepCount - 1);
|
||||
steps.add(new StepSegment(ramp.getEndAmplitude(), ramp.getEndFrequency(), duration));
|
||||
return steps;
|
||||
}
|
||||
|
||||
private static float interpolate(float start, float end, float position) {
|
||||
return start + position * (end - start);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter that clips frequency values to {@link VibratorInfo#getFrequencyRange()} and
|
||||
* amplitude values to respective {@link VibratorInfo#getMaxAmplitude}.
|
||||
*
|
||||
* <p>Devices with no frequency control will collapse all frequencies to zero and leave
|
||||
* amplitudes unchanged.
|
||||
*
|
||||
* <p>The frequency value returned in segments will be absolute, conveted with
|
||||
* {@link VibratorInfo#getAbsoluteFrequency(float)}.
|
||||
*/
|
||||
private static final class ClippingAmplitudeFrequencyAdapter implements SegmentsAdapter {
|
||||
@Override
|
||||
public int apply(List<VibrationEffectSegment> segments, int repeatIndex,
|
||||
VibratorInfo info) {
|
||||
int segmentCount = segments.size();
|
||||
for (int i = 0; i < segmentCount; i++) {
|
||||
VibrationEffectSegment segment = segments.get(i);
|
||||
if (segment instanceof StepSegment) {
|
||||
segments.set(i, apply((StepSegment) segment, info));
|
||||
} else if (segment instanceof RampSegment) {
|
||||
segments.set(i, apply((RampSegment) segment, info));
|
||||
}
|
||||
}
|
||||
return repeatIndex;
|
||||
}
|
||||
|
||||
private StepSegment apply(StepSegment segment, VibratorInfo info) {
|
||||
float clampedFrequency = info.getFrequencyRange().clamp(segment.getFrequency());
|
||||
return new StepSegment(
|
||||
MathUtils.min(segment.getAmplitude(), info.getMaxAmplitude(clampedFrequency)),
|
||||
info.getAbsoluteFrequency(clampedFrequency),
|
||||
(int) segment.getDuration());
|
||||
}
|
||||
|
||||
private RampSegment apply(RampSegment segment, VibratorInfo info) {
|
||||
Range<Float> frequencyRange = info.getFrequencyRange();
|
||||
float clampedStartFrequency = frequencyRange.clamp(segment.getStartFrequency());
|
||||
float clampedEndFrequency = frequencyRange.clamp(segment.getEndFrequency());
|
||||
return new RampSegment(
|
||||
MathUtils.min(segment.getStartAmplitude(),
|
||||
info.getMaxAmplitude(clampedStartFrequency)),
|
||||
MathUtils.min(segment.getEndAmplitude(),
|
||||
info.getMaxAmplitude(clampedEndFrequency)),
|
||||
info.getAbsoluteFrequency(clampedStartFrequency),
|
||||
info.getAbsoluteFrequency(clampedEndFrequency),
|
||||
(int) segment.getDuration());
|
||||
}
|
||||
return VibrationEffectAdapters.apply(effect, mSegmentAdapters, info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.hardware.vibrator.IVibrator;
|
||||
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 converts ramp segments that to a sequence of fixed step segments.
|
||||
*
|
||||
* <p>This leaves the list unchanged if the device have compose PWLE capability.
|
||||
*/
|
||||
final class RampToStepAdapter implements VibrationEffectAdapters.SegmentsAdapter<VibratorInfo> {
|
||||
|
||||
private final int mStepDuration;
|
||||
|
||||
RampToStepAdapter(int stepDuration) {
|
||||
mStepDuration = stepDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int apply(List<VibrationEffectSegment> segments, int repeatIndex,
|
||||
VibratorInfo info) {
|
||||
if (info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
|
||||
// The vibrator have PWLE capability, so keep the segments unchanged.
|
||||
return repeatIndex;
|
||||
}
|
||||
int segmentCount = segments.size();
|
||||
for (int i = 0; i < segmentCount; i++) {
|
||||
VibrationEffectSegment segment = segments.get(i);
|
||||
if (!(segment instanceof RampSegment)) {
|
||||
continue;
|
||||
}
|
||||
List<StepSegment> steps = apply((RampSegment) segment);
|
||||
segments.remove(i);
|
||||
segments.addAll(i, steps);
|
||||
int addedSegments = steps.size() - 1;
|
||||
if (repeatIndex > i) {
|
||||
repeatIndex += addedSegments;
|
||||
}
|
||||
i += addedSegments;
|
||||
segmentCount += addedSegments;
|
||||
}
|
||||
return repeatIndex;
|
||||
}
|
||||
|
||||
private List<StepSegment> apply(RampSegment ramp) {
|
||||
if (Float.compare(ramp.getStartAmplitude(), ramp.getEndAmplitude()) == 0) {
|
||||
// Amplitude is the same, so return a single step to simulate this ramp.
|
||||
return Arrays.asList(
|
||||
new StepSegment(ramp.getStartAmplitude(), ramp.getStartFrequency(),
|
||||
(int) ramp.getDuration()));
|
||||
}
|
||||
|
||||
List<StepSegment> steps = new ArrayList<>();
|
||||
int stepCount = (int) (ramp.getDuration() + mStepDuration - 1) / mStepDuration;
|
||||
for (int i = 0; i < stepCount - 1; i++) {
|
||||
float pos = (float) i / stepCount;
|
||||
steps.add(new StepSegment(
|
||||
interpolate(ramp.getStartAmplitude(), ramp.getEndAmplitude(), pos),
|
||||
interpolate(ramp.getStartFrequency(), ramp.getEndFrequency(), pos),
|
||||
mStepDuration));
|
||||
}
|
||||
int duration = (int) ramp.getDuration() - mStepDuration * (stepCount - 1);
|
||||
steps.add(new StepSegment(ramp.getEndAmplitude(), ramp.getEndFrequency(), duration));
|
||||
return steps;
|
||||
}
|
||||
|
||||
private static float interpolate(float start, float end, float position) {
|
||||
return start + position * (end - start);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.hardware.vibrator.IVibrator;
|
||||
import android.os.VibratorInfo;
|
||||
import android.os.vibrator.RampSegment;
|
||||
import android.os.vibrator.StepSegment;
|
||||
import android.os.vibrator.VibrationEffectSegment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Adapter that converts step segments that should be handled as PWLEs to ramp segments.
|
||||
*
|
||||
* <p>This leaves the list unchanged if the device do not have compose PWLE capability.
|
||||
*/
|
||||
final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter<VibratorInfo> {
|
||||
@Override
|
||||
public int apply(List<VibrationEffectSegment> segments, int repeatIndex,
|
||||
VibratorInfo info) {
|
||||
if (!info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
|
||||
// The vibrator do not have PWLE capability, so keep the segments unchanged.
|
||||
return repeatIndex;
|
||||
}
|
||||
int segmentCount = segments.size();
|
||||
// Convert steps that require frequency control to ramps.
|
||||
for (int i = 0; i < segmentCount; i++) {
|
||||
VibrationEffectSegment segment = segments.get(i);
|
||||
if ((segment instanceof StepSegment)
|
||||
&& ((StepSegment) segment).getFrequency() != 0) {
|
||||
segments.set(i, apply((StepSegment) segment));
|
||||
}
|
||||
}
|
||||
// Convert steps that are next to ramps to also become ramps, so they can be composed
|
||||
// together in the same PWLE waveform.
|
||||
for (int i = 1; i < segmentCount; i++) {
|
||||
if (segments.get(i) instanceof RampSegment) {
|
||||
for (int j = i - 1; j >= 0 && (segments.get(j) instanceof StepSegment); j--) {
|
||||
segments.set(j, apply((StepSegment) segments.get(j)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return repeatIndex;
|
||||
}
|
||||
|
||||
private RampSegment apply(StepSegment segment) {
|
||||
return new RampSegment(segment.getAmplitude(), segment.getAmplitude(),
|
||||
segment.getFrequency(), segment.getFrequency(), (int) segment.getDuration());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.VibrationEffect;
|
||||
import android.os.vibrator.VibrationEffectSegment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helpers to adapt a {@link VibrationEffect} to generic modifiers (e.g. device capabilities,
|
||||
* user settings, etc).
|
||||
*/
|
||||
public final class VibrationEffectAdapters {
|
||||
|
||||
/**
|
||||
* Function that applies a generic modifier to a sequence of {@link VibrationEffectSegment}.
|
||||
*
|
||||
* @param <T> The type of modifiers this adapter accepts.
|
||||
*/
|
||||
public interface SegmentsAdapter<T> {
|
||||
|
||||
/**
|
||||
* Add and/or remove segments to the given {@link VibrationEffectSegment} list based on the
|
||||
* given modifier.
|
||||
*
|
||||
* <p>This returns the new {@code repeatIndex} to be used together with the updated list to
|
||||
* specify an equivalent {@link VibrationEffect}.
|
||||
*
|
||||
* @param segments List of {@link VibrationEffectSegment} to be modified.
|
||||
* @param repeatIndex Repeat index on the current segment list.
|
||||
* @param modifier The modifier to be applied to the sequence of segments.
|
||||
* @return The new repeat index on the modifies list.
|
||||
*/
|
||||
int apply(List<VibrationEffectSegment> segments, int repeatIndex, T modifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that applies a generic modifier to a {@link VibrationEffect}.
|
||||
*
|
||||
* @param <T> The type of modifiers this adapter accepts.
|
||||
*/
|
||||
public interface EffectAdapter<T> {
|
||||
|
||||
/** Applies the modifier to given {@link VibrationEffect}, returning the new effect. */
|
||||
VibrationEffect apply(VibrationEffect effect, T modifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a sequence of {@link SegmentsAdapter} to the segments of a given
|
||||
* {@link VibrationEffect}, in order.
|
||||
*
|
||||
* @param effect The effect to be adapted to given modifier.
|
||||
* @param adapters The sequence of adapters to be applied to given {@link VibrationEffect}.
|
||||
* @param modifier The modifier to be passed to each adapter that describes the conditions the
|
||||
* {@link VibrationEffect} needs to be adapted to (e.g. device capabilities,
|
||||
* user settings, etc).
|
||||
*/
|
||||
public static <T> VibrationEffect apply(VibrationEffect effect,
|
||||
List<SegmentsAdapter<T>> adapters, T modifier) {
|
||||
if (!(effect instanceof VibrationEffect.Composed)) {
|
||||
// Segments adapters can only be applied to Composed effects.
|
||||
return effect;
|
||||
}
|
||||
|
||||
VibrationEffect.Composed composed = (VibrationEffect.Composed) effect;
|
||||
List<VibrationEffectSegment> newSegments = new ArrayList<>(composed.getSegments());
|
||||
int newRepeatIndex = composed.getRepeatIndex();
|
||||
|
||||
int adapterCount = adapters.size();
|
||||
for (int i = 0; i < adapterCount; i++) {
|
||||
newRepeatIndex = adapters.get(i).apply(newSegments, newRepeatIndex, modifier);
|
||||
}
|
||||
|
||||
return new VibrationEffect.Composed(newSegments, newRepeatIndex);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* 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.VibrationEffect;
|
||||
|
||||
/** Function that applies a generic modifier to a {@link VibrationEffect}. */
|
||||
interface VibrationEffectModifier<T> {
|
||||
|
||||
/** Applies the modifier to given {@link VibrationEffect}. */
|
||||
VibrationEffect apply(VibrationEffect effect, T modifier);
|
||||
}
|
||||
@@ -95,7 +95,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
|
||||
private final WorkSource mWorkSource = new WorkSource();
|
||||
private final PowerManager.WakeLock mWakeLock;
|
||||
private final IBatteryStats mBatteryStatsService;
|
||||
private final VibrationEffectModifier<VibratorInfo> mDeviceEffectAdapter =
|
||||
private final DeviceVibrationEffectAdapter mDeviceEffectAdapter =
|
||||
new DeviceVibrationEffectAdapter();
|
||||
private final Vibration mVibration;
|
||||
private final VibrationCallbacks mCallbacks;
|
||||
|
||||
Reference in New Issue
Block a user