• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.vibrator;
18 
19 import android.annotation.Nullable;
20 import android.os.Handler;
21 import android.os.Looper;
22 import android.os.VibrationEffect;
23 import android.os.VibratorInfo;
24 import android.os.vibrator.PrebakedSegment;
25 import android.os.vibrator.PrimitiveSegment;
26 import android.os.vibrator.RampSegment;
27 import android.os.vibrator.StepSegment;
28 import android.os.vibrator.VibrationEffectSegment;
29 
30 import com.android.server.vibrator.VibratorController.OnVibrationCompleteListener;
31 
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 
38 /**
39  * Provides {@link VibratorController} with controlled vibrator hardware capabilities and
40  * interactions.
41  */
42 final class FakeVibratorControllerProvider {
43     private static final int EFFECT_DURATION = 20;
44 
45     private final Map<Long, PrebakedSegment> mEnabledAlwaysOnEffects = new HashMap<>();
46     private final List<VibrationEffectSegment> mEffectSegments = new ArrayList<>();
47     private final List<Integer> mBraking = new ArrayList<>();
48     private final List<Float> mAmplitudes = new ArrayList<>();
49     private final List<Boolean> mExternalControlStates = new ArrayList<>();
50     private final Handler mHandler;
51     private final FakeNativeWrapper mNativeWrapper;
52 
53     private boolean mIsAvailable = true;
54     private long mLatency;
55 
56     private int mCapabilities;
57     private int[] mSupportedEffects;
58     private int[] mSupportedBraking;
59     private int[] mSupportedPrimitives;
60     private int mCompositionSizeMax;
61     private int mPwleSizeMax;
62     private float mMinFrequency = Float.NaN;
63     private float mResonantFrequency = Float.NaN;
64     private float mFrequencyResolution = Float.NaN;
65     private float mQFactor = Float.NaN;
66     private float[] mMaxAmplitudes;
67 
68     private final class FakeNativeWrapper extends VibratorController.NativeWrapper {
69         public int vibratorId;
70         public OnVibrationCompleteListener listener;
71         public boolean isInitialized;
72 
73         @Override
init(int vibratorId, OnVibrationCompleteListener listener)74         public void init(int vibratorId, OnVibrationCompleteListener listener) {
75             isInitialized = true;
76             this.vibratorId = vibratorId;
77             this.listener = listener;
78         }
79 
80         @Override
isAvailable()81         public boolean isAvailable() {
82             return mIsAvailable;
83         }
84 
85         @Override
on(long milliseconds, long vibrationId)86         public long on(long milliseconds, long vibrationId) {
87             mEffectSegments.add(new StepSegment(VibrationEffect.DEFAULT_AMPLITUDE,
88                     /* frequency= */ 0, (int) milliseconds));
89             applyLatency();
90             scheduleListener(milliseconds, vibrationId);
91             return milliseconds;
92         }
93 
94         @Override
off()95         public void off() {
96         }
97 
98         @Override
setAmplitude(float amplitude)99         public void setAmplitude(float amplitude) {
100             mAmplitudes.add(amplitude);
101             applyLatency();
102         }
103 
104         @Override
perform(long effect, long strength, long vibrationId)105         public long perform(long effect, long strength, long vibrationId) {
106             if (mSupportedEffects == null
107                     || Arrays.binarySearch(mSupportedEffects, (int) effect) < 0) {
108                 return 0;
109             }
110             mEffectSegments.add(new PrebakedSegment((int) effect, false, (int) strength));
111             applyLatency();
112             scheduleListener(EFFECT_DURATION, vibrationId);
113             return EFFECT_DURATION;
114         }
115 
116         @Override
compose(PrimitiveSegment[] effects, long vibrationId)117         public long compose(PrimitiveSegment[] effects, long vibrationId) {
118             long duration = 0;
119             for (PrimitiveSegment primitive : effects) {
120                 duration += EFFECT_DURATION + primitive.getDelay();
121                 mEffectSegments.add(primitive);
122             }
123             applyLatency();
124             scheduleListener(duration, vibrationId);
125             return duration;
126         }
127 
128         @Override
composePwle(RampSegment[] primitives, int braking, long vibrationId)129         public long composePwle(RampSegment[] primitives, int braking, long vibrationId) {
130             long duration = 0;
131             for (RampSegment primitive : primitives) {
132                 duration += primitive.getDuration();
133                 mEffectSegments.add(primitive);
134             }
135             mBraking.add(braking);
136             applyLatency();
137             scheduleListener(duration, vibrationId);
138             return duration;
139         }
140 
141         @Override
setExternalControl(boolean enabled)142         public void setExternalControl(boolean enabled) {
143             mExternalControlStates.add(enabled);
144         }
145 
146         @Override
alwaysOnEnable(long id, long effect, long strength)147         public void alwaysOnEnable(long id, long effect, long strength) {
148             PrebakedSegment prebaked = new PrebakedSegment((int) effect, false, (int) strength);
149             mEnabledAlwaysOnEffects.put(id, prebaked);
150         }
151 
152         @Override
alwaysOnDisable(long id)153         public void alwaysOnDisable(long id) {
154             mEnabledAlwaysOnEffects.remove(id);
155         }
156 
157         @Override
getInfo(float suggestedFrequencyRange, VibratorInfo.Builder infoBuilder)158         public boolean getInfo(float suggestedFrequencyRange, VibratorInfo.Builder infoBuilder) {
159             infoBuilder.setCapabilities(mCapabilities);
160             infoBuilder.setSupportedBraking(mSupportedBraking);
161             infoBuilder.setPwleSizeMax(mPwleSizeMax);
162             infoBuilder.setSupportedEffects(mSupportedEffects);
163             if (mSupportedPrimitives != null) {
164                 for (int primitive : mSupportedPrimitives) {
165                     infoBuilder.setSupportedPrimitive(primitive, EFFECT_DURATION);
166                 }
167             }
168             infoBuilder.setCompositionSizeMax(mCompositionSizeMax);
169             infoBuilder.setQFactor(mQFactor);
170             infoBuilder.setFrequencyMapping(new VibratorInfo.FrequencyMapping(mMinFrequency,
171                     mResonantFrequency, mFrequencyResolution, suggestedFrequencyRange,
172                     mMaxAmplitudes));
173             return true;
174         }
175 
applyLatency()176         private void applyLatency() {
177             try {
178                 if (mLatency > 0) {
179                     Thread.sleep(mLatency);
180                 }
181             } catch (InterruptedException e) {
182             }
183         }
184 
scheduleListener(long vibrationDuration, long vibrationId)185         private void scheduleListener(long vibrationDuration, long vibrationId) {
186             mHandler.postDelayed(() -> listener.onComplete(vibratorId, vibrationId),
187                     vibrationDuration);
188         }
189     }
190 
FakeVibratorControllerProvider(Looper looper)191     public FakeVibratorControllerProvider(Looper looper) {
192         mHandler = new Handler(looper);
193         mNativeWrapper = new FakeNativeWrapper();
194     }
195 
newVibratorController( int vibratorId, OnVibrationCompleteListener listener)196     public VibratorController newVibratorController(
197             int vibratorId, OnVibrationCompleteListener listener) {
198         return new VibratorController(vibratorId, listener, mNativeWrapper);
199     }
200 
201     /** Return {@code true} if this controller was initialized. */
isInitialized()202     public boolean isInitialized() {
203         return mNativeWrapper.isInitialized;
204     }
205 
206     /**
207      * Disable fake vibrator hardware, mocking a state where the underlying service is unavailable.
208      */
disableVibrators()209     public void disableVibrators() {
210         mIsAvailable = false;
211     }
212 
213     /**
214      * Sets the latency this controller should fake for turning the vibrator hardware on or setting
215      * it's vibration amplitude.
216      */
setLatency(long millis)217     public void setLatency(long millis) {
218         mLatency = millis;
219     }
220 
221     /** Set the capabilities of the fake vibrator hardware. */
setCapabilities(int... capabilities)222     public void setCapabilities(int... capabilities) {
223         mCapabilities = Arrays.stream(capabilities).reduce(0, (a, b) -> a | b);
224     }
225 
226     /** Set the effects supported by the fake vibrator hardware. */
setSupportedEffects(int... effects)227     public void setSupportedEffects(int... effects) {
228         if (effects != null) {
229             effects = Arrays.copyOf(effects, effects.length);
230             Arrays.sort(effects);
231         }
232         mSupportedEffects = effects;
233     }
234 
235     /** Set the effects supported by the fake vibrator hardware. */
setSupportedBraking(int... braking)236     public void setSupportedBraking(int... braking) {
237         if (braking != null) {
238             braking = Arrays.copyOf(braking, braking.length);
239             Arrays.sort(braking);
240         }
241         mSupportedBraking = braking;
242     }
243 
244     /** Set the primitives supported by the fake vibrator hardware. */
setSupportedPrimitives(int... primitives)245     public void setSupportedPrimitives(int... primitives) {
246         if (primitives != null) {
247             primitives = Arrays.copyOf(primitives, primitives.length);
248             Arrays.sort(primitives);
249         }
250         mSupportedPrimitives = primitives;
251     }
252 
253     /** Set the max number of primitives allowed in a composition by the fake vibrator hardware. */
setCompositionSizeMax(int compositionSizeMax)254     public void setCompositionSizeMax(int compositionSizeMax) {
255         mCompositionSizeMax = compositionSizeMax;
256     }
257 
258     /** Set the max number of PWLEs allowed in a composition by the fake vibrator hardware. */
setPwleSizeMax(int pwleSizeMax)259     public void setPwleSizeMax(int pwleSizeMax) {
260         mPwleSizeMax = pwleSizeMax;
261     }
262 
263     /** Set the resonant frequency of the fake vibrator hardware. */
setResonantFrequency(float frequencyHz)264     public void setResonantFrequency(float frequencyHz) {
265         mResonantFrequency = frequencyHz;
266     }
267 
268     /** Set the minimum frequency of the fake vibrator hardware. */
setMinFrequency(float frequencyHz)269     public void setMinFrequency(float frequencyHz) {
270         mMinFrequency = frequencyHz;
271     }
272 
273     /** Set the frequency resolution of the fake vibrator hardware. */
setFrequencyResolution(float frequencyHz)274     public void setFrequencyResolution(float frequencyHz) {
275         mFrequencyResolution = frequencyHz;
276     }
277 
278     /** Set the Q factor of the fake vibrator hardware. */
setQFactor(float qFactor)279     public void setQFactor(float qFactor) {
280         mQFactor = qFactor;
281     }
282 
283     /** Set the max amplitude supported for each frequency f the fake vibrator hardware. */
setMaxAmplitudes(float... maxAmplitudes)284     public void setMaxAmplitudes(float... maxAmplitudes) {
285         mMaxAmplitudes = maxAmplitudes;
286     }
287 
288     /**
289      * Return the amplitudes set by this controller, including zeroes for each time the vibrator was
290      * turned off.
291      */
getAmplitudes()292     public List<Float> getAmplitudes() {
293         return new ArrayList<>(mAmplitudes);
294     }
295 
296     /** Return the braking values passed to the compose PWLE method. */
getBraking()297     public List<Integer> getBraking() {
298         return mBraking;
299     }
300 
301     /** Return list of {@link VibrationEffectSegment} played by this controller, in order. */
getEffectSegments()302     public List<VibrationEffectSegment> getEffectSegments() {
303         return new ArrayList<>(mEffectSegments);
304     }
305 
306     /** Return list of states set for external control to the fake vibrator hardware. */
getExternalControlStates()307     public List<Boolean> getExternalControlStates() {
308         return mExternalControlStates;
309     }
310 
311     /**
312      * Return the {@link PrebakedSegment} effect enabled with given id, or {@code null} if
313      * missing or disabled.
314      */
315     @Nullable
getAlwaysOnEffect(int id)316     public PrebakedSegment getAlwaysOnEffect(int id) {
317         return mEnabledAlwaysOnEffects.get((long) id);
318     }
319 }
320