summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java80
-rw-r--r--services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java222
-rw-r--r--services/core/java/com/android/server/vibrator/RampToStepAdapter.java93
-rw-r--r--services/core/java/com/android/server/vibrator/StepToRampAdapter.java65
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationEffectAdapters.java92
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationEffectModifier.java26
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationThread.java2
7 files changed, 343 insertions, 237 deletions
diff --git a/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java b/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java
new file mode 100644
index 000000000000..0690d3be3db1
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java
@@ -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));
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java b/services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java
index 8eff2b9aab9e..b695150d9ba3 100644
--- a/services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java
+++ b/services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java
@@ -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);
}
}
diff --git a/services/core/java/com/android/server/vibrator/RampToStepAdapter.java b/services/core/java/com/android/server/vibrator/RampToStepAdapter.java
new file mode 100644
index 000000000000..1e05bdbdf082
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/RampToStepAdapter.java
@@ -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);
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/StepToRampAdapter.java b/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
new file mode 100644
index 000000000000..f78df9208fbd
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
@@ -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());
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibrationEffectAdapters.java b/services/core/java/com/android/server/vibrator/VibrationEffectAdapters.java
new file mode 100644
index 000000000000..446d9810ff19
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibrationEffectAdapters.java
@@ -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);
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibrationEffectModifier.java b/services/core/java/com/android/server/vibrator/VibrationEffectModifier.java
deleted file mode 100644
index d287c8faa34d..000000000000
--- a/services/core/java/com/android/server/vibrator/VibrationEffectModifier.java
+++ /dev/null
@@ -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);
-}
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index bc61478ec1b5..a33c546c866a 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -93,7 +93,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;