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 import java.util.TreeMap; 38 39 /** 40 * Provides {@link VibratorController} with controlled vibrator hardware capabilities and 41 * interactions. 42 */ 43 final class FakeVibratorControllerProvider { 44 private static final int EFFECT_DURATION = 20; 45 46 private final Map<Long, PrebakedSegment> mEnabledAlwaysOnEffects = new HashMap<>(); 47 private final Map<Long, List<VibrationEffectSegment>> mEffectSegments = new TreeMap<>(); 48 private final Map<Long, List<Integer>> mBraking = new HashMap<>(); 49 private final List<Float> mAmplitudes = new ArrayList<>(); 50 private final List<Boolean> mExternalControlStates = new ArrayList<>(); 51 private final Handler mHandler; 52 private final FakeNativeWrapper mNativeWrapper; 53 54 private boolean mIsAvailable = true; 55 private boolean mIsInfoLoadSuccessful = true; 56 private long mOnLatency; 57 private long mOffLatency; 58 private int mOffCount; 59 60 private int mCapabilities; 61 private int[] mSupportedEffects; 62 private int[] mSupportedBraking; 63 private int[] mSupportedPrimitives; 64 private int mCompositionSizeMax; 65 private int mPwleSizeMax; 66 private float mMinFrequency = Float.NaN; 67 private float mResonantFrequency = Float.NaN; 68 private float mFrequencyResolution = Float.NaN; 69 private float mQFactor = Float.NaN; 70 private float[] mMaxAmplitudes; 71 recordEffectSegment(long vibrationId, VibrationEffectSegment segment)72 void recordEffectSegment(long vibrationId, VibrationEffectSegment segment) { 73 mEffectSegments.computeIfAbsent(vibrationId, k -> new ArrayList<>()).add(segment); 74 } 75 recordBraking(long vibrationId, int braking)76 void recordBraking(long vibrationId, int braking) { 77 mBraking.computeIfAbsent(vibrationId, k -> new ArrayList<>()).add(braking); 78 } 79 80 private final class FakeNativeWrapper extends VibratorController.NativeWrapper { 81 public int vibratorId; 82 public OnVibrationCompleteListener listener; 83 public boolean isInitialized; 84 85 @Override init(int vibratorId, OnVibrationCompleteListener listener)86 public void init(int vibratorId, OnVibrationCompleteListener listener) { 87 isInitialized = true; 88 this.vibratorId = vibratorId; 89 this.listener = listener; 90 } 91 92 @Override isAvailable()93 public boolean isAvailable() { 94 return mIsAvailable; 95 } 96 97 @Override on(long milliseconds, long vibrationId)98 public long on(long milliseconds, long vibrationId) { 99 recordEffectSegment(vibrationId, new StepSegment(VibrationEffect.DEFAULT_AMPLITUDE, 100 /* frequencyHz= */ 0, (int) milliseconds)); 101 applyLatency(mOnLatency); 102 scheduleListener(milliseconds, vibrationId); 103 return milliseconds; 104 } 105 106 @Override off()107 public void off() { 108 mOffCount++; 109 applyLatency(mOffLatency); 110 } 111 112 @Override setAmplitude(float amplitude)113 public void setAmplitude(float amplitude) { 114 mAmplitudes.add(amplitude); 115 applyLatency(mOnLatency); 116 } 117 118 @Override perform(long effect, long strength, long vibrationId)119 public long perform(long effect, long strength, long vibrationId) { 120 if (mSupportedEffects == null 121 || Arrays.binarySearch(mSupportedEffects, (int) effect) < 0) { 122 return 0; 123 } 124 recordEffectSegment(vibrationId, 125 new PrebakedSegment((int) effect, false, (int) strength)); 126 applyLatency(mOnLatency); 127 scheduleListener(EFFECT_DURATION, vibrationId); 128 return EFFECT_DURATION; 129 } 130 131 @Override compose(PrimitiveSegment[] primitives, long vibrationId)132 public long compose(PrimitiveSegment[] primitives, long vibrationId) { 133 if (mSupportedPrimitives == null) { 134 return 0; 135 } 136 for (PrimitiveSegment primitive : primitives) { 137 if (Arrays.binarySearch(mSupportedPrimitives, primitive.getPrimitiveId()) < 0) { 138 return 0; 139 } 140 } 141 long duration = 0; 142 for (PrimitiveSegment primitive : primitives) { 143 duration += EFFECT_DURATION + primitive.getDelay(); 144 recordEffectSegment(vibrationId, primitive); 145 } 146 applyLatency(mOnLatency); 147 scheduleListener(duration, vibrationId); 148 return duration; 149 } 150 151 @Override composePwle(RampSegment[] primitives, int braking, long vibrationId)152 public long composePwle(RampSegment[] primitives, int braking, long vibrationId) { 153 long duration = 0; 154 for (RampSegment primitive : primitives) { 155 duration += primitive.getDuration(); 156 recordEffectSegment(vibrationId, primitive); 157 } 158 recordBraking(vibrationId, braking); 159 applyLatency(mOnLatency); 160 scheduleListener(duration, vibrationId); 161 return duration; 162 } 163 164 @Override setExternalControl(boolean enabled)165 public void setExternalControl(boolean enabled) { 166 mExternalControlStates.add(enabled); 167 } 168 169 @Override alwaysOnEnable(long id, long effect, long strength)170 public void alwaysOnEnable(long id, long effect, long strength) { 171 PrebakedSegment prebaked = new PrebakedSegment((int) effect, false, (int) strength); 172 mEnabledAlwaysOnEffects.put(id, prebaked); 173 } 174 175 @Override alwaysOnDisable(long id)176 public void alwaysOnDisable(long id) { 177 mEnabledAlwaysOnEffects.remove(id); 178 } 179 180 @Override getInfo(VibratorInfo.Builder infoBuilder)181 public boolean getInfo(VibratorInfo.Builder infoBuilder) { 182 infoBuilder.setCapabilities(mCapabilities); 183 infoBuilder.setSupportedBraking(mSupportedBraking); 184 infoBuilder.setPwleSizeMax(mPwleSizeMax); 185 infoBuilder.setSupportedEffects(mSupportedEffects); 186 if (mSupportedPrimitives != null) { 187 for (int primitive : mSupportedPrimitives) { 188 infoBuilder.setSupportedPrimitive(primitive, EFFECT_DURATION); 189 } 190 } 191 infoBuilder.setCompositionSizeMax(mCompositionSizeMax); 192 infoBuilder.setQFactor(mQFactor); 193 infoBuilder.setFrequencyProfile(new VibratorInfo.FrequencyProfile( 194 mResonantFrequency, mMinFrequency, mFrequencyResolution, mMaxAmplitudes)); 195 return mIsInfoLoadSuccessful; 196 } 197 applyLatency(long latencyMillis)198 private void applyLatency(long latencyMillis) { 199 try { 200 if (latencyMillis > 0) { 201 Thread.sleep(latencyMillis); 202 } 203 } catch (InterruptedException e) { 204 } 205 } 206 scheduleListener(long vibrationDuration, long vibrationId)207 private void scheduleListener(long vibrationDuration, long vibrationId) { 208 mHandler.postDelayed(() -> listener.onComplete(vibratorId, vibrationId), 209 vibrationDuration); 210 } 211 } 212 FakeVibratorControllerProvider(Looper looper)213 public FakeVibratorControllerProvider(Looper looper) { 214 mHandler = new Handler(looper); 215 mNativeWrapper = new FakeNativeWrapper(); 216 } 217 newVibratorController( int vibratorId, OnVibrationCompleteListener listener)218 public VibratorController newVibratorController( 219 int vibratorId, OnVibrationCompleteListener listener) { 220 return new VibratorController(vibratorId, listener, mNativeWrapper); 221 } 222 223 /** Return {@code true} if this controller was initialized. */ isInitialized()224 public boolean isInitialized() { 225 return mNativeWrapper.isInitialized; 226 } 227 228 /** 229 * Disable fake vibrator hardware, mocking a state where the underlying service is unavailable. 230 */ disableVibrators()231 public void disableVibrators() { 232 mIsAvailable = false; 233 } 234 235 /** 236 * Sets the result for the method that loads the {@link VibratorInfo}, for faking a vibrator 237 * that fails to load some of the hardware data. 238 */ setVibratorInfoLoadSuccessful(boolean successful)239 public void setVibratorInfoLoadSuccessful(boolean successful) { 240 mIsInfoLoadSuccessful = successful; 241 } 242 243 /** 244 * Sets the latency this controller should fake for turning the vibrator hardware on or setting 245 * the vibration amplitude. 246 */ setOnLatency(long millis)247 public void setOnLatency(long millis) { 248 mOnLatency = millis; 249 } 250 251 /** Sets the latency this controller should fake for turning the vibrator off. */ setOffLatency(long millis)252 public void setOffLatency(long millis) { 253 mOffLatency = millis; 254 } 255 256 /** Set the capabilities of the fake vibrator hardware. */ setCapabilities(int... capabilities)257 public void setCapabilities(int... capabilities) { 258 mCapabilities = Arrays.stream(capabilities).reduce(0, (a, b) -> a | b); 259 } 260 261 /** Set the effects supported by the fake vibrator hardware. */ setSupportedEffects(int... effects)262 public void setSupportedEffects(int... effects) { 263 if (effects != null) { 264 effects = Arrays.copyOf(effects, effects.length); 265 Arrays.sort(effects); 266 } 267 mSupportedEffects = effects; 268 } 269 270 /** Set the effects supported by the fake vibrator hardware. */ setSupportedBraking(int... braking)271 public void setSupportedBraking(int... braking) { 272 if (braking != null) { 273 braking = Arrays.copyOf(braking, braking.length); 274 Arrays.sort(braking); 275 } 276 mSupportedBraking = braking; 277 } 278 279 /** Set the primitives supported by the fake vibrator hardware. */ setSupportedPrimitives(int... primitives)280 public void setSupportedPrimitives(int... primitives) { 281 if (primitives != null) { 282 primitives = Arrays.copyOf(primitives, primitives.length); 283 Arrays.sort(primitives); 284 } 285 mSupportedPrimitives = primitives; 286 } 287 288 /** Set the max number of primitives allowed in a composition by the fake vibrator hardware. */ setCompositionSizeMax(int compositionSizeMax)289 public void setCompositionSizeMax(int compositionSizeMax) { 290 mCompositionSizeMax = compositionSizeMax; 291 } 292 293 /** Set the max number of PWLEs allowed in a composition by the fake vibrator hardware. */ setPwleSizeMax(int pwleSizeMax)294 public void setPwleSizeMax(int pwleSizeMax) { 295 mPwleSizeMax = pwleSizeMax; 296 } 297 298 /** Set the resonant frequency of the fake vibrator hardware. */ setResonantFrequency(float frequencyHz)299 public void setResonantFrequency(float frequencyHz) { 300 mResonantFrequency = frequencyHz; 301 } 302 303 /** Set the minimum frequency of the fake vibrator hardware. */ setMinFrequency(float frequencyHz)304 public void setMinFrequency(float frequencyHz) { 305 mMinFrequency = frequencyHz; 306 } 307 308 /** Set the frequency resolution of the fake vibrator hardware. */ setFrequencyResolution(float frequencyHz)309 public void setFrequencyResolution(float frequencyHz) { 310 mFrequencyResolution = frequencyHz; 311 } 312 313 /** Set the Q factor of the fake vibrator hardware. */ setQFactor(float qFactor)314 public void setQFactor(float qFactor) { 315 mQFactor = qFactor; 316 } 317 318 /** Set the max amplitude supported for each frequency f the fake vibrator hardware. */ setMaxAmplitudes(float... maxAmplitudes)319 public void setMaxAmplitudes(float... maxAmplitudes) { 320 mMaxAmplitudes = maxAmplitudes; 321 } 322 323 /** 324 * Return the amplitudes set by this controller, including zeroes for each time the vibrator was 325 * turned off. 326 */ getAmplitudes()327 public List<Float> getAmplitudes() { 328 return new ArrayList<>(mAmplitudes); 329 } 330 331 /** Return the braking values passed to the compose PWLE method. */ getBraking(long vibrationId)332 public List<Integer> getBraking(long vibrationId) { 333 if (mBraking.containsKey(vibrationId)) { 334 return new ArrayList<>(mBraking.get(vibrationId)); 335 } else { 336 return new ArrayList<>(); 337 } 338 } 339 340 /** Return list of {@link VibrationEffectSegment} played by this controller, in order. */ getEffectSegments(long vibrationId)341 public List<VibrationEffectSegment> getEffectSegments(long vibrationId) { 342 if (mEffectSegments.containsKey(vibrationId)) { 343 return new ArrayList<>(mEffectSegments.get(vibrationId)); 344 } else { 345 return new ArrayList<>(); 346 } 347 } 348 349 /** 350 * Returns a list of all vibrations' effect segments, for external-use where vibration IDs 351 * aren't exposed. 352 */ getAllEffectSegments()353 public List<VibrationEffectSegment> getAllEffectSegments() { 354 // Returns segments in order of vibrationId, which increases over time. TreeMap gives order. 355 ArrayList<VibrationEffectSegment> result = new ArrayList<>(); 356 for (List<VibrationEffectSegment> subList : mEffectSegments.values()) { 357 result.addAll(subList); 358 } 359 return result; 360 } 361 /** Return list of states set for external control to the fake vibrator hardware. */ getExternalControlStates()362 public List<Boolean> getExternalControlStates() { 363 return mExternalControlStates; 364 } 365 366 /** Returns the number of times the vibrator was turned off. */ getOffCount()367 public int getOffCount() { 368 return mOffCount; 369 } 370 371 /** 372 * Return the {@link PrebakedSegment} effect enabled with given id, or {@code null} if 373 * missing or disabled. 374 */ 375 @Nullable getAlwaysOnEffect(int id)376 public PrebakedSegment getAlwaysOnEffect(int id) { 377 return mEnabledAlwaysOnEffects.get((long) id); 378 } 379 } 380