xref: /aosp_15_r20/hardware/interfaces/vibrator/aidl/default/Vibrator.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1 /*
2  * Copyright (C) 2019 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 #include "vibrator-impl/Vibrator.h"
18 
19 #include <android-base/logging.h>
20 #include <thread>
21 
22 namespace aidl {
23 namespace android {
24 namespace hardware {
25 namespace vibrator {
26 
27 static constexpr int32_t COMPOSE_DELAY_MAX_MS = 1000;
28 static constexpr int32_t COMPOSE_SIZE_MAX = 256;
29 static constexpr int32_t COMPOSE_PWLE_SIZE_MAX = 127;
30 static constexpr int32_t COMPOSE_PWLE_V2_SIZE_MAX = 16;
31 
32 static constexpr float Q_FACTOR = 11.0;
33 static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 16383;
34 static constexpr int32_t COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS = 1000;
35 static constexpr int32_t COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MIN_MS = 20;
36 static constexpr float PWLE_LEVEL_MIN = 0.0;
37 static constexpr float PWLE_LEVEL_MAX = 1.0;
38 static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 1.0;
39 static constexpr float PWLE_FREQUENCY_MIN_HZ = 140.0;
40 static constexpr float RESONANT_FREQUENCY_HZ = 150.0;
41 static constexpr float PWLE_FREQUENCY_MAX_HZ = 160.0;
42 static constexpr float PWLE_BW_MAP_SIZE =
43         1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ);
44 
45 // Service specific error code used for vendor vibration effects.
46 static constexpr int32_t ERROR_CODE_INVALID_DURATION = 1;
47 
dispatchVibrate(int32_t timeoutMs,const std::shared_ptr<IVibratorCallback> & callback)48 void Vibrator::dispatchVibrate(int32_t timeoutMs,
49                                const std::shared_ptr<IVibratorCallback>& callback) {
50     std::lock_guard lock(mMutex);
51     if (mIsVibrating) {
52         // Already vibrating, ignore new request.
53         return;
54     }
55     mVibrationCallback = callback;
56     mIsVibrating = true;
57     // Note that thread lambdas aren't using implicit capture [=], to avoid capturing "this",
58     // which may be asynchronously destructed.
59     std::thread([timeoutMs, callback, sharedThis = this->ref<Vibrator>()] {
60         LOG(VERBOSE) << "Starting delayed callback on another thread";
61         usleep(timeoutMs * 1000);
62 
63         if (sharedThis) {
64             std::lock_guard lock(sharedThis->mMutex);
65             sharedThis->mIsVibrating = false;
66             if (sharedThis->mVibrationCallback && (callback == sharedThis->mVibrationCallback)) {
67                 LOG(VERBOSE) << "Notifying callback onComplete";
68                 if (!sharedThis->mVibrationCallback->onComplete().isOk()) {
69                     LOG(ERROR) << "Failed to call onComplete";
70                 }
71                 sharedThis->mVibrationCallback = nullptr;
72             }
73             if (sharedThis->mGlobalVibrationCallback) {
74                 LOG(VERBOSE) << "Notifying global callback onComplete";
75                 if (!sharedThis->mGlobalVibrationCallback->onComplete().isOk()) {
76                     LOG(ERROR) << "Failed to call onComplete";
77                 }
78                 sharedThis->mGlobalVibrationCallback = nullptr;
79             }
80         }
81     }).detach();
82 }
83 
setGlobalVibrationCallback(const std::shared_ptr<IVibratorCallback> & callback)84 void Vibrator::setGlobalVibrationCallback(const std::shared_ptr<IVibratorCallback>& callback) {
85     std::lock_guard lock(mMutex);
86     if (mIsVibrating) {
87         mGlobalVibrationCallback = callback;
88     } else if (callback) {
89         std::thread([callback] {
90             LOG(VERBOSE) << "Notifying global callback onComplete";
91             if (!callback->onComplete().isOk()) {
92                 LOG(ERROR) << "Failed to call onComplete";
93             }
94         }).detach();
95     }
96 }
97 
getCapabilities(int32_t * _aidl_return)98 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
99     LOG(VERBOSE) << "Vibrator reporting capabilities";
100     std::lock_guard lock(mMutex);
101     if (mCapabilities == 0) {
102         int32_t version;
103         if (!getInterfaceVersion(&version).isOk()) {
104             return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
105         }
106         mCapabilities = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
107                         IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
108                         IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
109                         IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
110                         IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
111                         IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
112 
113         if (version >= 3) {
114             mCapabilities |=
115                     IVibrator::CAP_PERFORM_VENDOR_EFFECTS | IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2;
116         }
117     }
118 
119     *_aidl_return = mCapabilities;
120     return ndk::ScopedAStatus::ok();
121 }
122 
off()123 ndk::ScopedAStatus Vibrator::off() {
124     LOG(VERBOSE) << "Vibrator off";
125     std::lock_guard lock(mMutex);
126     std::shared_ptr<IVibratorCallback> callback = mVibrationCallback;
127     std::shared_ptr<IVibratorCallback> globalCallback = mGlobalVibrationCallback;
128     mIsVibrating = false;
129     mVibrationCallback = nullptr;
130     mGlobalVibrationCallback = nullptr;
131     if (callback || globalCallback) {
132         std::thread([callback, globalCallback] {
133             if (callback) {
134                 LOG(VERBOSE) << "Notifying callback onComplete";
135                 if (!callback->onComplete().isOk()) {
136                     LOG(ERROR) << "Failed to call onComplete";
137                 }
138             }
139             if (globalCallback) {
140                 LOG(VERBOSE) << "Notifying global callback onComplete";
141                 if (!globalCallback->onComplete().isOk()) {
142                     LOG(ERROR) << "Failed to call onComplete";
143                 }
144             }
145         }).detach();
146     }
147     return ndk::ScopedAStatus::ok();
148 }
149 
on(int32_t timeoutMs,const std::shared_ptr<IVibratorCallback> & callback)150 ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
151                                 const std::shared_ptr<IVibratorCallback>& callback) {
152     LOG(VERBOSE) << "Vibrator on for timeoutMs: " << timeoutMs;
153     dispatchVibrate(timeoutMs, callback);
154     return ndk::ScopedAStatus::ok();
155 }
156 
perform(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * _aidl_return)157 ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
158                                      const std::shared_ptr<IVibratorCallback>& callback,
159                                      int32_t* _aidl_return) {
160     LOG(VERBOSE) << "Vibrator perform";
161 
162     if (effect != Effect::CLICK && effect != Effect::TICK) {
163         return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
164     }
165     if (strength != EffectStrength::LIGHT && strength != EffectStrength::MEDIUM &&
166         strength != EffectStrength::STRONG) {
167         return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
168     }
169 
170     constexpr size_t kEffectMillis = 100;
171     dispatchVibrate(kEffectMillis, callback);
172     *_aidl_return = kEffectMillis;
173     return ndk::ScopedAStatus::ok();
174 }
175 
performVendorEffect(const VendorEffect & effect,const std::shared_ptr<IVibratorCallback> & callback)176 ndk::ScopedAStatus Vibrator::performVendorEffect(
177         const VendorEffect& effect, const std::shared_ptr<IVibratorCallback>& callback) {
178     LOG(VERBOSE) << "Vibrator perform vendor effect";
179     int32_t capabilities = 0;
180     if (!getCapabilities(&capabilities).isOk()) {
181         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
182     }
183     if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) {
184         return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
185     }
186     EffectStrength strength = effect.strength;
187     if (strength != EffectStrength::LIGHT && strength != EffectStrength::MEDIUM &&
188         strength != EffectStrength::STRONG) {
189         return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
190     }
191     float scale = effect.scale;
192     if (scale <= 0) {
193         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
194     }
195     float vendorScale = effect.vendorScale;
196     if (vendorScale <= 0) {
197         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
198     }
199 
200     int32_t durationMs = 0;
201     if (!effect.vendorData.getInt("DURATION_MS", &durationMs) || durationMs <= 0) {
202         return ndk::ScopedAStatus::fromServiceSpecificError(ERROR_CODE_INVALID_DURATION);
203     }
204 
205     dispatchVibrate(durationMs, callback);
206     return ndk::ScopedAStatus::ok();
207 }
208 
getSupportedEffects(std::vector<Effect> * _aidl_return)209 ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
210     *_aidl_return = {Effect::CLICK, Effect::TICK};
211     return ndk::ScopedAStatus::ok();
212 }
213 
setAmplitude(float amplitude)214 ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
215     LOG(VERBOSE) << "Vibrator set amplitude: " << amplitude;
216     if (amplitude <= 0.0f || amplitude > 1.0f) {
217         return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
218     }
219     return ndk::ScopedAStatus::ok();
220 }
221 
setExternalControl(bool enabled)222 ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
223     LOG(VERBOSE) << "Vibrator set external control: " << enabled;
224     return ndk::ScopedAStatus::ok();
225 }
226 
getCompositionDelayMax(int32_t * maxDelayMs)227 ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* maxDelayMs) {
228     *maxDelayMs = COMPOSE_DELAY_MAX_MS;
229     return ndk::ScopedAStatus::ok();
230 }
231 
getCompositionSizeMax(int32_t * maxSize)232 ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize) {
233     *maxSize = COMPOSE_SIZE_MAX;
234     return ndk::ScopedAStatus::ok();
235 }
236 
getSupportedPrimitives(std::vector<CompositePrimitive> * supported)237 ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* supported) {
238     *supported = {
239             CompositePrimitive::NOOP,       CompositePrimitive::CLICK,
240             CompositePrimitive::THUD,       CompositePrimitive::SPIN,
241             CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
242             CompositePrimitive::QUICK_FALL, CompositePrimitive::LIGHT_TICK,
243             CompositePrimitive::LOW_TICK,
244     };
245     return ndk::ScopedAStatus::ok();
246 }
247 
getPrimitiveDuration(CompositePrimitive primitive,int32_t * durationMs)248 ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
249                                                   int32_t* durationMs) {
250     std::vector<CompositePrimitive> supported;
251     getSupportedPrimitives(&supported);
252     if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) {
253         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
254     }
255     if (primitive != CompositePrimitive::NOOP) {
256         *durationMs = 100;
257     } else {
258         *durationMs = 0;
259     }
260     return ndk::ScopedAStatus::ok();
261 }
262 
compose(const std::vector<CompositeEffect> & composite,const std::shared_ptr<IVibratorCallback> & callback)263 ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite,
264                                      const std::shared_ptr<IVibratorCallback>& callback) {
265     if (composite.size() > COMPOSE_SIZE_MAX) {
266         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
267     }
268 
269     std::vector<CompositePrimitive> supported;
270     getSupportedPrimitives(&supported);
271 
272     for (auto& e : composite) {
273         if (e.delayMs > COMPOSE_DELAY_MAX_MS) {
274             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
275         }
276         if (e.scale < 0.0f || e.scale > 1.0f) {
277             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
278         }
279         if (std::find(supported.begin(), supported.end(), e.primitive) == supported.end()) {
280             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
281         }
282     }
283 
284     int32_t totalDuration = 0;
285     for (auto& e : composite) {
286         int32_t durationMs;
287         getPrimitiveDuration(e.primitive, &durationMs);
288         totalDuration += e.delayMs + durationMs;
289     }
290 
291     dispatchVibrate(totalDuration, callback);
292     return ndk::ScopedAStatus::ok();
293 }
294 
getSupportedAlwaysOnEffects(std::vector<Effect> * _aidl_return)295 ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) {
296     return getSupportedEffects(_aidl_return);
297 }
298 
alwaysOnEnable(int32_t id,Effect effect,EffectStrength strength)299 ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
300     std::vector<Effect> effects;
301     getSupportedAlwaysOnEffects(&effects);
302 
303     if (std::find(effects.begin(), effects.end(), effect) == effects.end()) {
304         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
305     } else {
306         LOG(VERBOSE) << "Enabling always-on ID " << id << " with " << toString(effect) << "/"
307                      << toString(strength);
308         return ndk::ScopedAStatus::ok();
309     }
310 }
311 
alwaysOnDisable(int32_t id)312 ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) {
313     LOG(VERBOSE) << "Disabling always-on ID " << id;
314     return ndk::ScopedAStatus::ok();
315 }
316 
getResonantFrequency(float * resonantFreqHz)317 ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) {
318     *resonantFreqHz = RESONANT_FREQUENCY_HZ;
319     return ndk::ScopedAStatus::ok();
320 }
321 
getQFactor(float * qFactor)322 ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor) {
323     *qFactor = Q_FACTOR;
324     return ndk::ScopedAStatus::ok();
325 }
326 
getFrequencyResolution(float * freqResolutionHz)327 ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz) {
328     *freqResolutionHz = PWLE_FREQUENCY_RESOLUTION_HZ;
329     return ndk::ScopedAStatus::ok();
330 }
331 
getFrequencyMinimum(float * freqMinimumHz)332 ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float *freqMinimumHz) {
333     *freqMinimumHz = PWLE_FREQUENCY_MIN_HZ;
334     return ndk::ScopedAStatus::ok();
335 }
336 
getBandwidthAmplitudeMap(std::vector<float> * _aidl_return)337 ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) {
338     // The output BandwidthAmplitudeMap will be as below and the maximum
339     // amplitude 1.0 will be set on RESONANT_FREQUENCY_HZ
340     // {0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1, 0.99, 0.98, 0.97,
341     // 0.96, 0.95, 0.94, 0.93, 0.92, 0.91, 0.9}
342     int32_t capabilities = 0;
343     int halfMapSize = PWLE_BW_MAP_SIZE / 2;
344     Vibrator::getCapabilities(&capabilities);
345     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
346         std::vector<float> bandwidthAmplitudeMap(PWLE_BW_MAP_SIZE, PWLE_LEVEL_MAX);
347         for (int i = 0; i < halfMapSize; ++i) {
348             bandwidthAmplitudeMap[halfMapSize + i + 1] =
349                     bandwidthAmplitudeMap[halfMapSize + i] - 0.01;
350             bandwidthAmplitudeMap[halfMapSize - i - 1] =
351                     bandwidthAmplitudeMap[halfMapSize - i] - 0.01;
352         }
353         *_aidl_return = bandwidthAmplitudeMap;
354         return ndk::ScopedAStatus::ok();
355     } else {
356         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
357     }
358 }
359 
getPwlePrimitiveDurationMax(int32_t * durationMs)360 ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs) {
361     *durationMs = COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS;
362     return ndk::ScopedAStatus::ok();
363 }
364 
getPwleCompositionSizeMax(int32_t * maxSize)365 ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize) {
366     *maxSize = COMPOSE_PWLE_SIZE_MAX;
367     return ndk::ScopedAStatus::ok();
368 }
369 
getSupportedBraking(std::vector<Braking> * supported)370 ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> *supported) {
371     *supported = {
372             Braking::NONE,
373             Braking::CLAB,
374     };
375     return ndk::ScopedAStatus::ok();
376 }
377 
resetPreviousEndAmplitudeEndFrequency(float & prevEndAmplitude,float & prevEndFrequency)378 void resetPreviousEndAmplitudeEndFrequency(float &prevEndAmplitude, float &prevEndFrequency) {
379     const float reset = -1.0;
380     prevEndAmplitude = reset;
381     prevEndFrequency = reset;
382 }
383 
incrementIndex(int & index)384 void incrementIndex(int &index) {
385     index += 1;
386 }
387 
constructActiveDefaults(std::ostringstream & pwleBuilder,const int & segmentIdx)388 void constructActiveDefaults(std::ostringstream &pwleBuilder, const int &segmentIdx) {
389     pwleBuilder << ",C" << segmentIdx << ":1";
390     pwleBuilder << ",B" << segmentIdx << ":0";
391     pwleBuilder << ",AR" << segmentIdx << ":0";
392     pwleBuilder << ",V" << segmentIdx << ":0";
393 }
394 
constructActiveSegment(std::ostringstream & pwleBuilder,const int & segmentIdx,int duration,float amplitude,float frequency)395 void constructActiveSegment(std::ostringstream &pwleBuilder, const int &segmentIdx, int duration,
396                             float amplitude, float frequency) {
397     pwleBuilder << ",T" << segmentIdx << ":" << duration;
398     pwleBuilder << ",L" << segmentIdx << ":" << amplitude;
399     pwleBuilder << ",F" << segmentIdx << ":" << frequency;
400     constructActiveDefaults(pwleBuilder, segmentIdx);
401 }
402 
constructBrakingSegment(std::ostringstream & pwleBuilder,const int & segmentIdx,int duration,Braking brakingType)403 void constructBrakingSegment(std::ostringstream &pwleBuilder, const int &segmentIdx, int duration,
404                              Braking brakingType) {
405     pwleBuilder << ",T" << segmentIdx << ":" << duration;
406     pwleBuilder << ",L" << segmentIdx << ":" << 0;
407     pwleBuilder << ",F" << segmentIdx << ":" << 0;
408     pwleBuilder << ",C" << segmentIdx << ":0";
409     pwleBuilder << ",B" << segmentIdx << ":"
410                 << static_cast<std::underlying_type<Braking>::type>(brakingType);
411     pwleBuilder << ",AR" << segmentIdx << ":0";
412     pwleBuilder << ",V" << segmentIdx << ":0";
413 }
414 
composePwle(const std::vector<PrimitivePwle> & composite,const std::shared_ptr<IVibratorCallback> & callback)415 ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &composite,
416                                          const std::shared_ptr<IVibratorCallback> &callback) {
417     std::ostringstream pwleBuilder;
418     std::string pwleQueue;
419 
420     int compositionSizeMax;
421     getPwleCompositionSizeMax(&compositionSizeMax);
422     if (composite.size() <= 0 || composite.size() > compositionSizeMax) {
423         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
424     }
425 
426     float prevEndAmplitude;
427     float prevEndFrequency;
428     resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency);
429 
430     int segmentIdx = 0;
431     uint32_t totalDuration = 0;
432 
433     pwleBuilder << "S:0,WF:4,RP:0,WT:0";
434 
435     for (auto &e : composite) {
436         switch (e.getTag()) {
437             case PrimitivePwle::active: {
438                 auto active = e.get<PrimitivePwle::active>();
439                 if (active.duration < 0 ||
440                     active.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
441                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
442                 }
443                 if (active.startAmplitude < PWLE_LEVEL_MIN ||
444                     active.startAmplitude > PWLE_LEVEL_MAX ||
445                     active.endAmplitude < PWLE_LEVEL_MIN || active.endAmplitude > PWLE_LEVEL_MAX) {
446                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
447                 }
448                 if (active.startFrequency < PWLE_FREQUENCY_MIN_HZ ||
449                     active.startFrequency > PWLE_FREQUENCY_MAX_HZ ||
450                     active.endFrequency < PWLE_FREQUENCY_MIN_HZ ||
451                     active.endFrequency > PWLE_FREQUENCY_MAX_HZ) {
452                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
453                 }
454 
455                 if (!((active.startAmplitude == prevEndAmplitude) &&
456                       (active.startFrequency == prevEndFrequency))) {
457                     constructActiveSegment(pwleBuilder, segmentIdx, 0, active.startAmplitude,
458                                            active.startFrequency);
459                     incrementIndex(segmentIdx);
460                 }
461 
462                 constructActiveSegment(pwleBuilder, segmentIdx, active.duration,
463                                        active.endAmplitude, active.endFrequency);
464                 incrementIndex(segmentIdx);
465 
466                 prevEndAmplitude = active.endAmplitude;
467                 prevEndFrequency = active.endFrequency;
468                 totalDuration += active.duration;
469                 break;
470             }
471             case PrimitivePwle::braking: {
472                 auto braking = e.get<PrimitivePwle::braking>();
473                 if (braking.braking > Braking::CLAB) {
474                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
475                 }
476                 if (braking.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
477                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
478                 }
479 
480                 constructBrakingSegment(pwleBuilder, segmentIdx, 0, braking.braking);
481                 incrementIndex(segmentIdx);
482 
483                 constructBrakingSegment(pwleBuilder, segmentIdx, braking.duration, braking.braking);
484                 incrementIndex(segmentIdx);
485 
486                 resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency);
487                 totalDuration += braking.duration;
488                 break;
489             }
490         }
491     }
492 
493     dispatchVibrate(totalDuration, callback);
494     return ndk::ScopedAStatus::ok();
495 }
496 
getFrequencyToOutputAccelerationMap(std::vector<FrequencyAccelerationMapEntry> * _aidl_return)497 ndk::ScopedAStatus Vibrator::getFrequencyToOutputAccelerationMap(
498         std::vector<FrequencyAccelerationMapEntry>* _aidl_return) {
499     int32_t capabilities = 0;
500     if (!getCapabilities(&capabilities).isOk()) {
501         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
502     }
503     if (!(capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) {
504         return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
505     }
506 
507     std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
508 
509     std::vector<std::pair<float, float>> frequencyToOutputAccelerationData = {
510             {30.0f, 0.01f},  {46.0f, 0.09f},  {50.0f, 0.1f},   {55.0f, 0.12f},  {62.0f, 0.66f},
511             {83.0f, 0.82f},  {85.0f, 0.85f},  {92.0f, 1.05f},  {107.0f, 1.63f}, {115.0f, 1.72f},
512             {123.0f, 1.81f}, {135.0f, 2.23f}, {144.0f, 2.47f}, {145.0f, 2.5f},  {150.0f, 3.0f},
513             {175.0f, 2.51f}, {181.0f, 2.41f}, {190.0f, 2.28f}, {200.0f, 2.08f}, {204.0f, 1.96f},
514             {205.0f, 1.9f},  {224.0f, 1.7f},  {235.0f, 1.5f},  {242.0f, 1.46f}, {253.0f, 1.41f},
515             {263.0f, 1.39f}, {65.0f, 1.38f},  {278.0f, 1.37f}, {294.0f, 1.35f}, {300.0f, 1.34f}};
516     for (const auto& entry : frequencyToOutputAccelerationData) {
517         frequencyToOutputAccelerationMap.push_back(
518                 FrequencyAccelerationMapEntry(/*frequency=*/entry.first,
519                                               /*maxOutputAcceleration=*/entry.second));
520     }
521 
522     *_aidl_return = frequencyToOutputAccelerationMap;
523 
524     return ndk::ScopedAStatus::ok();
525 }
526 
getPwleV2PrimitiveDurationMaxMillis(int32_t * maxDurationMs)527 ndk::ScopedAStatus Vibrator::getPwleV2PrimitiveDurationMaxMillis(int32_t* maxDurationMs) {
528     *maxDurationMs = COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS;
529     return ndk::ScopedAStatus::ok();
530 }
531 
getPwleV2CompositionSizeMax(int32_t * maxSize)532 ndk::ScopedAStatus Vibrator::getPwleV2CompositionSizeMax(int32_t* maxSize) {
533     *maxSize = COMPOSE_PWLE_V2_SIZE_MAX;
534     return ndk::ScopedAStatus::ok();
535 }
536 
getPwleV2PrimitiveDurationMinMillis(int32_t * minDurationMs)537 ndk::ScopedAStatus Vibrator::getPwleV2PrimitiveDurationMinMillis(int32_t* minDurationMs) {
538     *minDurationMs = COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MIN_MS;
539     return ndk::ScopedAStatus::ok();
540 }
541 
getPwleV2FrequencyMinHz(std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap)542 float getPwleV2FrequencyMinHz(
543         std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap) {
544     if (frequencyToOutputAccelerationMap.empty()) {
545         return 0.0f;
546     }
547 
548     float minFrequency = frequencyToOutputAccelerationMap[0].frequencyHz;
549 
550     for (const auto& entry : frequencyToOutputAccelerationMap) {
551         if (entry.frequencyHz < minFrequency) {
552             minFrequency = entry.frequencyHz;
553         }
554     }
555 
556     return minFrequency;
557 }
558 
getPwleV2FrequencyMaxHz(std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap)559 float getPwleV2FrequencyMaxHz(
560         std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap) {
561     if (frequencyToOutputAccelerationMap.empty()) {
562         return 0.0f;
563     }
564 
565     float maxFrequency = frequencyToOutputAccelerationMap[0].frequencyHz;
566 
567     for (const auto& entry : frequencyToOutputAccelerationMap) {
568         if (entry.frequencyHz > maxFrequency) {
569             maxFrequency = entry.frequencyHz;
570         }
571     }
572 
573     return maxFrequency;
574 }
575 
composePwleV2(const CompositePwleV2 & composite,const std::shared_ptr<IVibratorCallback> & callback)576 ndk::ScopedAStatus Vibrator::composePwleV2(const CompositePwleV2& composite,
577                                            const std::shared_ptr<IVibratorCallback>& callback) {
578     LOG(VERBOSE) << "Vibrator compose PWLE V2";
579     int32_t capabilities = 0;
580     if (!getCapabilities(&capabilities).isOk()) {
581         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
582     }
583     if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) ||
584         !(capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) {
585         return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
586     }
587 
588     int compositionSizeMax;
589     getPwleV2CompositionSizeMax(&compositionSizeMax);
590     if (composite.pwlePrimitives.empty() || composite.pwlePrimitives.size() > compositionSizeMax) {
591         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
592     }
593 
594     int32_t totalEffectDuration = 0;
595     std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
596     getFrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap);
597     float minFrequency = getPwleV2FrequencyMinHz(frequencyToOutputAccelerationMap);
598     float maxFrequency = getPwleV2FrequencyMaxHz(frequencyToOutputAccelerationMap);
599 
600     for (auto& e : composite.pwlePrimitives) {
601         if (e.timeMillis < 0.0f || e.timeMillis > COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS) {
602             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
603         }
604         if (e.amplitude < 0.0f || e.amplitude > 1.0f) {
605             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
606         }
607         if (e.frequencyHz < minFrequency || e.frequencyHz > maxFrequency) {
608             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
609         }
610         totalEffectDuration += e.timeMillis;
611     }
612 
613     dispatchVibrate(totalEffectDuration, callback);
614     return ndk::ScopedAStatus::ok();
615 }
616 
617 }  // namespace vibrator
618 }  // namespace hardware
619 }  // namespace android
620 }  // namespace aidl
621