• 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.hardware.vibrator.IVibrator;
21 import android.os.Handler;
22 import android.os.Looper;
23 import android.os.Parcel;
24 import android.os.PersistableBundle;
25 import android.os.VibrationEffect;
26 import android.os.VibratorInfo;
27 import android.os.vibrator.PrebakedSegment;
28 import android.os.vibrator.PrimitiveSegment;
29 import android.os.vibrator.PwlePoint;
30 import android.os.vibrator.RampSegment;
31 import android.os.vibrator.StepSegment;
32 import android.os.vibrator.VibrationEffectSegment;
33 
34 import com.android.server.vibrator.VibratorController.OnVibrationCompleteListener;
35 
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.HashMap;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.TreeMap;
42 
43 /**
44  * Provides {@link VibratorController} with configurable vibrator hardware capabilities and
45  * fake interactions for tests.
46  */
47 public final class FakeVibratorControllerProvider {
48     private static final int EFFECT_DURATION = 20;
49 
50     private final Map<Long, PrebakedSegment> mEnabledAlwaysOnEffects = new HashMap<>();
51     private final Map<Long, List<VibrationEffectSegment>> mEffectSegments = new TreeMap<>();
52     private final Map<Long, List<VibrationEffect.VendorEffect>> mVendorEffects = new TreeMap<>();
53     private final Map<Long, List<PwlePoint>> mEffectPwlePoints = new TreeMap<>();
54     private final Map<Long, List<Integer>> mBraking = new HashMap<>();
55     private final List<Float> mAmplitudes = new ArrayList<>();
56     private final List<Boolean> mExternalControlStates = new ArrayList<>();
57     private final Handler mHandler;
58     private final FakeNativeWrapper mNativeWrapper;
59 
60     private boolean mIsAvailable = true;
61     private boolean mIsInfoLoadSuccessful = true;
62     private long mCompletionCallbackDelay;
63     private long mOnLatency;
64     private long mOffLatency;
65     private int mOffCount;
66 
67     private int mCapabilities;
68     private int[] mSupportedEffects;
69     private int[] mSupportedBraking;
70     private int[] mSupportedPrimitives;
71     private int mCompositionSizeMax;
72     private int mPwleSizeMax;
73     private int mMaxEnvelopeEffectSize;
74     private int mMinEnvelopeEffectControlPointDurationMillis;
75     private int mMaxEnvelopeEffectControlPointDurationMillis;
76     private float mMinFrequency = Float.NaN;
77     private float mResonantFrequency = Float.NaN;
78     private float mFrequencyResolution = Float.NaN;
79     private float mQFactor = Float.NaN;
80     private float[] mMaxAmplitudes;
81 
82     private float[] mFrequenciesHz;
83     private float[] mOutputAccelerationsGs;
84     private long mVendorEffectDuration = EFFECT_DURATION;
85     private long mPrimitiveDuration = EFFECT_DURATION;
86 
recordEffectSegment(long vibrationId, VibrationEffectSegment segment)87     void recordEffectSegment(long vibrationId, VibrationEffectSegment segment) {
88         mEffectSegments.computeIfAbsent(vibrationId, k -> new ArrayList<>()).add(segment);
89     }
90 
recordVendorEffect(long vibrationId, VibrationEffect.VendorEffect vendorEffect)91     void recordVendorEffect(long vibrationId, VibrationEffect.VendorEffect vendorEffect) {
92         mVendorEffects.computeIfAbsent(vibrationId, k -> new ArrayList<>()).add(vendorEffect);
93     }
94 
recordEffectPwlePoint(long vibrationId, PwlePoint pwlePoint)95     void recordEffectPwlePoint(long vibrationId, PwlePoint pwlePoint) {
96         mEffectPwlePoints.computeIfAbsent(vibrationId, k -> new ArrayList<>()).add(pwlePoint);
97     }
98 
recordBraking(long vibrationId, int braking)99     void recordBraking(long vibrationId, int braking) {
100         mBraking.computeIfAbsent(vibrationId, k -> new ArrayList<>()).add(braking);
101     }
102 
103     private final class FakeNativeWrapper extends VibratorController.NativeWrapper {
104         public int vibratorId;
105         public OnVibrationCompleteListener listener;
106         public boolean isInitialized;
107 
108         @Override
init(int vibratorId, OnVibrationCompleteListener listener)109         public void init(int vibratorId, OnVibrationCompleteListener listener) {
110             isInitialized = true;
111             this.vibratorId = vibratorId;
112             this.listener = listener;
113         }
114 
115         @Override
isAvailable()116         public boolean isAvailable() {
117             return mIsAvailable;
118         }
119 
120         @Override
on(long milliseconds, long vibrationId, long stepId)121         public long on(long milliseconds, long vibrationId, long stepId) {
122             recordEffectSegment(vibrationId, new StepSegment(VibrationEffect.DEFAULT_AMPLITUDE,
123                     /* frequencyHz= */ 0, (int) milliseconds));
124             applyLatency(mOnLatency);
125             scheduleListener(milliseconds, vibrationId, stepId);
126             return milliseconds;
127         }
128 
129         @Override
off()130         public void off() {
131             mOffCount++;
132             applyLatency(mOffLatency);
133         }
134 
135         @Override
setAmplitude(float amplitude)136         public void setAmplitude(float amplitude) {
137             mAmplitudes.add(amplitude);
138             applyLatency(mOnLatency);
139         }
140 
141         @Override
perform(long effect, long strength, long vibrationId, long stepId)142         public long perform(long effect, long strength, long vibrationId, long stepId) {
143             if (mSupportedEffects == null
144                     || Arrays.binarySearch(mSupportedEffects, (int) effect) < 0) {
145                 return 0;
146             }
147             recordEffectSegment(vibrationId,
148                     new PrebakedSegment((int) effect, false, (int) strength));
149             applyLatency(mOnLatency);
150             scheduleListener(EFFECT_DURATION, vibrationId, stepId);
151             return EFFECT_DURATION;
152         }
153 
154         @Override
performVendorEffect(Parcel vendorData, long strength, float scale, float adaptiveScale, long vibrationId, long stepId)155         public long performVendorEffect(Parcel vendorData, long strength, float scale,
156                 float adaptiveScale, long vibrationId, long stepId) {
157             if ((mCapabilities & IVibrator.CAP_PERFORM_VENDOR_EFFECTS) == 0) {
158                 return 0;
159             }
160             PersistableBundle bundle = PersistableBundle.CREATOR.createFromParcel(vendorData);
161             recordVendorEffect(vibrationId,
162                     new VibrationEffect.VendorEffect(bundle, (int) strength, scale, adaptiveScale));
163             applyLatency(mOnLatency);
164             scheduleListener(mVendorEffectDuration, vibrationId, stepId);
165             // HAL has unknown duration for vendor effects.
166             return Long.MAX_VALUE;
167         }
168 
169         @Override
compose(PrimitiveSegment[] primitives, long vibrationId, long stepId)170         public long compose(PrimitiveSegment[] primitives, long vibrationId, long stepId) {
171             if (mSupportedPrimitives == null) {
172                 return 0;
173             }
174             for (PrimitiveSegment primitive : primitives) {
175                 if (Arrays.binarySearch(mSupportedPrimitives, primitive.getPrimitiveId()) < 0) {
176                     return 0;
177                 }
178             }
179             long duration = 0;
180             for (PrimitiveSegment primitive : primitives) {
181                 duration += mPrimitiveDuration + primitive.getDelay();
182                 recordEffectSegment(vibrationId, primitive);
183             }
184             applyLatency(mOnLatency);
185             scheduleListener(duration, vibrationId, stepId);
186             return duration;
187         }
188 
189         @Override
composePwle(RampSegment[] primitives, int braking, long vibrationId, long stepId)190         public long composePwle(RampSegment[] primitives, int braking, long vibrationId,
191                 long stepId) {
192             long duration = 0;
193             for (RampSegment primitive : primitives) {
194                 duration += primitive.getDuration();
195                 recordEffectSegment(vibrationId, primitive);
196             }
197             recordBraking(vibrationId, braking);
198             applyLatency(mOnLatency);
199             scheduleListener(duration, vibrationId, stepId);
200             return duration;
201         }
202 
203         @Override
composePwleV2(PwlePoint[] pwlePoints, long vibrationId, long stepId)204         public long composePwleV2(PwlePoint[] pwlePoints, long vibrationId, long stepId) {
205             long duration = 0;
206             for (PwlePoint pwlePoint: pwlePoints) {
207                 duration += pwlePoint.getTimeMillis();
208                 recordEffectPwlePoint(vibrationId, pwlePoint);
209             }
210             applyLatency(mOnLatency);
211             scheduleListener(duration, vibrationId, stepId);
212 
213             return duration;
214         }
215 
216         @Override
setExternalControl(boolean enabled)217         public void setExternalControl(boolean enabled) {
218             mExternalControlStates.add(enabled);
219         }
220 
221         @Override
alwaysOnEnable(long id, long effect, long strength)222         public void alwaysOnEnable(long id, long effect, long strength) {
223             PrebakedSegment prebaked = new PrebakedSegment((int) effect, false, (int) strength);
224             mEnabledAlwaysOnEffects.put(id, prebaked);
225         }
226 
227         @Override
alwaysOnDisable(long id)228         public void alwaysOnDisable(long id) {
229             mEnabledAlwaysOnEffects.remove(id);
230         }
231 
232         @Override
getInfo(VibratorInfo.Builder infoBuilder)233         public boolean getInfo(VibratorInfo.Builder infoBuilder) {
234             infoBuilder.setCapabilities(mCapabilities);
235             infoBuilder.setSupportedBraking(mSupportedBraking);
236             infoBuilder.setPwleSizeMax(mPwleSizeMax);
237             infoBuilder.setSupportedEffects(mSupportedEffects);
238             if (mSupportedPrimitives != null) {
239                 for (int primitive : mSupportedPrimitives) {
240                     infoBuilder.setSupportedPrimitive(primitive, (int) mPrimitiveDuration);
241                 }
242             }
243             infoBuilder.setCompositionSizeMax(mCompositionSizeMax);
244             infoBuilder.setQFactor(mQFactor);
245             infoBuilder.setFrequencyProfileLegacy(new VibratorInfo.FrequencyProfileLegacy(
246                     mResonantFrequency, mMinFrequency, mFrequencyResolution, mMaxAmplitudes));
247             infoBuilder.setFrequencyProfile(
248                     new VibratorInfo.FrequencyProfile(mResonantFrequency, mFrequenciesHz,
249                             mOutputAccelerationsGs));
250             infoBuilder.setMaxEnvelopeEffectSize(mMaxEnvelopeEffectSize);
251             infoBuilder.setMinEnvelopeEffectControlPointDurationMillis(
252                     mMinEnvelopeEffectControlPointDurationMillis);
253             infoBuilder.setMaxEnvelopeEffectControlPointDurationMillis(
254                     mMaxEnvelopeEffectControlPointDurationMillis);
255             return mIsInfoLoadSuccessful;
256         }
257 
applyLatency(long latencyMillis)258         private void applyLatency(long latencyMillis) {
259             try {
260                 if (latencyMillis > 0) {
261                     Thread.sleep(latencyMillis);
262                 }
263             } catch (InterruptedException e) {
264             }
265         }
266 
scheduleListener(long vibrationDuration, long vibrationId, long stepId)267         private void scheduleListener(long vibrationDuration, long vibrationId, long stepId) {
268             mHandler.postDelayed(() -> listener.onComplete(vibratorId, vibrationId, stepId),
269                     vibrationDuration + mCompletionCallbackDelay);
270         }
271     }
272 
FakeVibratorControllerProvider(Looper looper)273     public FakeVibratorControllerProvider(Looper looper) {
274         mHandler = new Handler(looper);
275         mNativeWrapper = new FakeNativeWrapper();
276     }
277 
newVibratorController( int vibratorId, OnVibrationCompleteListener listener)278     public VibratorController newVibratorController(
279             int vibratorId, OnVibrationCompleteListener listener) {
280         return new VibratorController(vibratorId, listener, mNativeWrapper);
281     }
282 
283     /** Return {@code true} if this controller was initialized. */
isInitialized()284     public boolean isInitialized() {
285         return mNativeWrapper.isInitialized;
286     }
287 
288     /**
289      * Disable fake vibrator hardware, mocking a state where the underlying service is unavailable.
290      */
disableVibrators()291     public void disableVibrators() {
292         mIsAvailable = false;
293     }
294 
295     /**
296      * Sets the result for the method that loads the {@link VibratorInfo}, for faking a vibrator
297      * that fails to load some of the hardware data.
298      */
setVibratorInfoLoadSuccessful(boolean successful)299     public void setVibratorInfoLoadSuccessful(boolean successful) {
300         mIsInfoLoadSuccessful = successful;
301     }
302 
303     /**
304      * Sets the delay this controller should fake for triggering the vibration completed callback.
305      */
setCompletionCallbackDelay(long millis)306     public void setCompletionCallbackDelay(long millis) {
307         mCompletionCallbackDelay = millis;
308     }
309 
310     /**
311      * Sets the latency this controller should fake for turning the vibrator hardware on or setting
312      * the vibration amplitude.
313      */
setOnLatency(long millis)314     public void setOnLatency(long millis) {
315         mOnLatency = millis;
316     }
317 
318     /** Sets the latency this controller should fake for turning the vibrator off. */
setOffLatency(long millis)319     public void setOffLatency(long millis) {
320         mOffLatency = millis;
321     }
322 
323     /** Set the capabilities of the fake vibrator hardware. */
setCapabilities(int... capabilities)324     public void setCapabilities(int... capabilities) {
325         mCapabilities = Arrays.stream(capabilities).reduce(0, (a, b) -> a | b);
326     }
327 
328     /** Set the effects supported by the fake vibrator hardware. */
setSupportedEffects(int... effects)329     public void setSupportedEffects(int... effects) {
330         if (effects != null) {
331             effects = Arrays.copyOf(effects, effects.length);
332             Arrays.sort(effects);
333         }
334         mSupportedEffects = effects;
335     }
336 
337     /** Set the effects supported by the fake vibrator hardware. */
setSupportedBraking(int... braking)338     public void setSupportedBraking(int... braking) {
339         if (braking != null) {
340             braking = Arrays.copyOf(braking, braking.length);
341             Arrays.sort(braking);
342         }
343         mSupportedBraking = braking;
344     }
345 
346     /** Set the primitives supported by the fake vibrator hardware. */
setSupportedPrimitives(int... primitives)347     public void setSupportedPrimitives(int... primitives) {
348         if (primitives != null) {
349             primitives = Arrays.copyOf(primitives, primitives.length);
350             Arrays.sort(primitives);
351         }
352         mSupportedPrimitives = primitives;
353     }
354 
355     /** Set the max number of primitives allowed in a composition by the fake vibrator hardware. */
setCompositionSizeMax(int compositionSizeMax)356     public void setCompositionSizeMax(int compositionSizeMax) {
357         mCompositionSizeMax = compositionSizeMax;
358     }
359 
360     /** Set the max number of PWLEs allowed in a composition by the fake vibrator hardware. */
setPwleSizeMax(int pwleSizeMax)361     public void setPwleSizeMax(int pwleSizeMax) {
362         mPwleSizeMax = pwleSizeMax;
363     }
364 
365     /** Set the resonant frequency of the fake vibrator hardware. */
setResonantFrequency(float frequencyHz)366     public void setResonantFrequency(float frequencyHz) {
367         mResonantFrequency = frequencyHz;
368     }
369 
370     /** Set the minimum frequency of the fake vibrator hardware. */
setMinFrequency(float frequencyHz)371     public void setMinFrequency(float frequencyHz) {
372         mMinFrequency = frequencyHz;
373     }
374 
375     /** Set the frequency resolution of the fake vibrator hardware. */
setFrequencyResolution(float frequencyHz)376     public void setFrequencyResolution(float frequencyHz) {
377         mFrequencyResolution = frequencyHz;
378     }
379 
380     /** Set the Q factor of the fake vibrator hardware. */
setQFactor(float qFactor)381     public void setQFactor(float qFactor) {
382         mQFactor = qFactor;
383     }
384 
385     /** Set the max amplitude supported for each frequency f the fake vibrator hardware. */
setMaxAmplitudes(float... maxAmplitudes)386     public void setMaxAmplitudes(float... maxAmplitudes) {
387         mMaxAmplitudes = maxAmplitudes;
388     }
389 
390     /** Set the list of available frequencies. */
setFrequenciesHz(float[] frequenciesHz)391     public void setFrequenciesHz(float[] frequenciesHz) {
392         mFrequenciesHz = frequenciesHz;
393     }
394 
395     /** Set the max output acceleration achievable by the supported frequencies. */
setOutputAccelerationsGs(float[] outputAccelerationsGs)396     public void setOutputAccelerationsGs(float[] outputAccelerationsGs) {
397         mOutputAccelerationsGs = outputAccelerationsGs;
398     }
399 
400     /** Set the duration of vendor effects in fake vibrator hardware. */
setVendorEffectDuration(long durationMs)401     public void setVendorEffectDuration(long durationMs) {
402         mVendorEffectDuration = durationMs;
403     }
404 
405     /** Set the duration of primitives in fake vibrator hardware. */
setPrimitiveDuration(long primitiveDuration)406     public void setPrimitiveDuration(long primitiveDuration) {
407         mPrimitiveDuration = primitiveDuration;
408     }
409 
410     /**
411      * Set the maximum number of envelope effects control points supported in fake vibrator
412      * hardware.
413      */
setMaxEnvelopeEffectSize(int envelopeEffectControlPointsMax)414     public void setMaxEnvelopeEffectSize(int envelopeEffectControlPointsMax) {
415         mMaxEnvelopeEffectSize = envelopeEffectControlPointsMax;
416     }
417 
418     /** Set the envelope effect minimum segment duration in fake vibrator hardware. */
setMinEnvelopeEffectControlPointDurationMillis( int minEnvelopeEffectControlPointDurationMillis)419     public void setMinEnvelopeEffectControlPointDurationMillis(
420             int minEnvelopeEffectControlPointDurationMillis) {
421         mMinEnvelopeEffectControlPointDurationMillis = minEnvelopeEffectControlPointDurationMillis;
422     }
423 
424     /** Set the envelope effect maximum segment duration in fake vibrator hardware. */
setMaxEnvelopeEffectControlPointDurationMillis( int maxEnvelopeEffectControlPointDurationMillis)425     public void setMaxEnvelopeEffectControlPointDurationMillis(
426             int maxEnvelopeEffectControlPointDurationMillis) {
427         mMaxEnvelopeEffectControlPointDurationMillis = maxEnvelopeEffectControlPointDurationMillis;
428     }
429 
430     /**
431      * Return the amplitudes set by this controller, including zeroes for each time the vibrator was
432      * turned off.
433      */
getAmplitudes()434     public List<Float> getAmplitudes() {
435         return new ArrayList<>(mAmplitudes);
436     }
437 
438     /** Return the braking values passed to the compose PWLE method. */
getBraking(long vibrationId)439     public List<Integer> getBraking(long vibrationId) {
440         if (mBraking.containsKey(vibrationId)) {
441             return new ArrayList<>(mBraking.get(vibrationId));
442         } else {
443             return new ArrayList<>();
444         }
445     }
446 
447     /** Return list of {@link VibrationEffectSegment} played by this controller, in order. */
getEffectSegments(long vibrationId)448     public List<VibrationEffectSegment> getEffectSegments(long vibrationId) {
449         if (mEffectSegments.containsKey(vibrationId)) {
450             return new ArrayList<>(mEffectSegments.get(vibrationId));
451         } else {
452             return new ArrayList<>();
453         }
454     }
455 
456     /**
457      * Returns a list of all vibrations' effect segments, for external-use where vibration IDs
458      * aren't exposed.
459      */
getAllEffectSegments()460     public List<VibrationEffectSegment> getAllEffectSegments() {
461         // Returns segments in order of vibrationId, which increases over time. TreeMap gives order.
462         ArrayList<VibrationEffectSegment> result = new ArrayList<>();
463         for (List<VibrationEffectSegment> subList : mEffectSegments.values()) {
464             result.addAll(subList);
465         }
466         return result;
467     }
468 
469     /** Return list of {@link VibrationEffect.VendorEffect} played by this controller, in order. */
getVendorEffects(long vibrationId)470     public List<VibrationEffect.VendorEffect> getVendorEffects(long vibrationId) {
471         if (mVendorEffects.containsKey(vibrationId)) {
472             return new ArrayList<>(mVendorEffects.get(vibrationId));
473         } else {
474             return new ArrayList<>();
475         }
476     }
477 
478     /**
479      * Returns a list of all vibrations' effect segments, for external-use where vibration IDs
480      * aren't exposed.
481      */
getAllVendorEffects()482     public List<VibrationEffect.VendorEffect> getAllVendorEffects() {
483         // Returns segments in order of vibrationId, which increases over time. TreeMap gives order.
484         ArrayList<VibrationEffect.VendorEffect> result = new ArrayList<>();
485         for (List<VibrationEffect.VendorEffect> subList : mVendorEffects.values()) {
486             result.addAll(subList);
487         }
488         return result;
489     }
490 
491     /** Return list of {@link PwlePoint} played by this controller, in order. */
getEffectPwlePoints(long vibrationId)492     public List<PwlePoint> getEffectPwlePoints(long vibrationId) {
493         if (mEffectPwlePoints.containsKey(vibrationId)) {
494             return new ArrayList<>(mEffectPwlePoints.get(vibrationId));
495         } else {
496             return new ArrayList<>();
497         }
498     }
499 
500     /**
501      * Returns a list of all vibrations' {@link PwlePoint}s, for external-use where vibration
502      * IDs aren't exposed.
503      */
getAllEffectPwlePoints()504     public List<PwlePoint> getAllEffectPwlePoints() {
505         // Returns segments in order of vibrationId, which increases over time. TreeMap gives order.
506         ArrayList<PwlePoint> result = new ArrayList<>();
507         for (List<PwlePoint> subList : mEffectPwlePoints.values()) {
508             result.addAll(subList);
509         }
510         return result;
511     }
512 
513     /** Return list of states set for external control to the fake vibrator hardware. */
getExternalControlStates()514     public List<Boolean> getExternalControlStates() {
515         return mExternalControlStates;
516     }
517 
518     /** Returns the number of times the vibrator was turned off. */
getOffCount()519     public int getOffCount() {
520         return mOffCount;
521     }
522 
523     /**
524      * Return the {@link PrebakedSegment} effect enabled with given id, or {@code null} if
525      * missing or disabled.
526      */
527     @Nullable
getAlwaysOnEffect(int id)528     public PrebakedSegment getAlwaysOnEffect(int id) {
529         return mEnabledAlwaysOnEffects.get((long) id);
530     }
531 }
532