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