blob: 11d7ff09bf7cb8c587ffc52b0c812d96ab18ca06 [file] [log] [blame]
Tim Zimmermann1bc99f52021-11-23 20:45:19 +01001/*
SamarV-12131d105a2023-01-25 16:00:10 +05302 * Copyright (C) 2021-2023 The LineageOS Project
Tim Zimmermann1bc99f52021-11-23 20:45:19 +01003 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include "Vibrator.h"
8
9#include <android-base/logging.h>
10
11#include <cmath>
12#include <fstream>
13#include <iostream>
Tim Zimmermann428bd3e2022-01-31 12:01:42 +010014#include <map>
Tim Zimmermann1bc99f52021-11-23 20:45:19 +010015#include <thread>
16
17namespace aidl {
18namespace android {
19namespace hardware {
20namespace vibrator {
21
Tim Zimmermann428bd3e2022-01-31 12:01:42 +010022static std::map<Effect, int> CP_TRIGGER_EFFECTS {
23 { Effect::CLICK, 10 },
24 { Effect::DOUBLE_CLICK, 14 },
25 { Effect::HEAVY_CLICK, 23 },
26 { Effect::TEXTURE_TICK, 50 },
27 { Effect::TICK, 50 }
28};
29
Tim Zimmermann1bc99f52021-11-23 20:45:19 +010030/*
31 * Write value to path and close file.
32 */
33template <typename T>
34static ndk::ScopedAStatus writeNode(const std::string& path, const T& value) {
35 std::ofstream node(path);
36 if (!node) {
37 LOG(ERROR) << "Failed to open: " << path;
38 return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_ERROR);
39 }
40
41 LOG(DEBUG) << "writeNode node: " << path << " value: " << value;
42
43 node << value << std::endl;
44 if (!node) {
45 LOG(ERROR) << "Failed to write: " << value;
46 return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_ERROR);
47 }
48
49 return ndk::ScopedAStatus::ok();
50}
51
52static bool nodeExists(const std::string& path) {
53 std::ofstream f(path.c_str());
54 return f.good();
55}
56
57Vibrator::Vibrator() {
58 mIsTimedOutVibrator = nodeExists(VIBRATOR_TIMEOUT_PATH);
59 mHasTimedOutIntensity = nodeExists(VIBRATOR_INTENSITY_PATH);
Tim Zimmermann428bd3e2022-01-31 12:01:42 +010060 mHasTimedOutEffect = nodeExists(VIBRATOR_CP_TRIGGER_PATH);
Tim Zimmermann1bc99f52021-11-23 20:45:19 +010061}
62
63ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
64 *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
65 IVibrator::CAP_EXTERNAL_CONTROL /*| IVibrator::CAP_COMPOSE_EFFECTS |
66 IVibrator::CAP_ALWAYS_ON_CONTROL*/;
67
68 if (mHasTimedOutIntensity) {
69 *_aidl_return = *_aidl_return | IVibrator::CAP_AMPLITUDE_CONTROL |
70 IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL;
71 }
72
73 return ndk::ScopedAStatus::ok();
74}
75
76ndk::ScopedAStatus Vibrator::off() {
77 return activate(0);
78}
79
80ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, const std::shared_ptr<IVibratorCallback>& callback) {
Tim Zimmermann428bd3e2022-01-31 12:01:42 +010081 ndk::ScopedAStatus status;
82
83 if (mHasTimedOutEffect)
84 writeNode(VIBRATOR_CP_TRIGGER_PATH, 0); // Clear all effects
85
86 status = activate(timeoutMs);
Tim Zimmermann1bc99f52021-11-23 20:45:19 +010087
88 if (callback != nullptr) {
89 std::thread([=] {
Tim Zimmermann428bd3e2022-01-31 12:01:42 +010090 LOG(DEBUG) << "Starting on on another thread";
Tim Zimmermann1bc99f52021-11-23 20:45:19 +010091 usleep(timeoutMs * 1000);
Tim Zimmermann428bd3e2022-01-31 12:01:42 +010092 LOG(DEBUG) << "Notifying on complete";
Tim Zimmermann1bc99f52021-11-23 20:45:19 +010093 if (!callback->onComplete().isOk()) {
94 LOG(ERROR) << "Failed to call onComplete";
95 }
96 }).detach();
97 }
98
99 return status;
100}
101
102ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength, const std::shared_ptr<IVibratorCallback>& callback, int32_t* _aidl_return) {
103 ndk::ScopedAStatus status;
SamarV-12131d105a2023-01-25 16:00:10 +0530104 float amplitude = strengthToAmplitude(strength, &status);
Tim Zimmermann428bd3e2022-01-31 12:01:42 +0100105 uint32_t ms = 1000;
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100106
Tim Zimmermann428bd3e2022-01-31 12:01:42 +0100107 if (!status.isOk())
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100108 return status;
Tim Zimmermann428bd3e2022-01-31 12:01:42 +0100109
110 activate(0);
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100111 setAmplitude(amplitude);
112
Tim Zimmermann428bd3e2022-01-31 12:01:42 +0100113 if (mHasTimedOutEffect && CP_TRIGGER_EFFECTS.find(effect) != CP_TRIGGER_EFFECTS.end()) {
114 writeNode(VIBRATOR_CP_TRIGGER_PATH, CP_TRIGGER_EFFECTS[effect]);
115 } else {
116 if (mHasTimedOutEffect)
117 writeNode(VIBRATOR_CP_TRIGGER_PATH, 0); // Clear previous effect
118
119 ms = effectToMs(effect, &status);
120
121 if (!status.isOk())
122 return status;
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100123 }
Tim Zimmermann428bd3e2022-01-31 12:01:42 +0100124
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100125 status = activate(ms);
126
127 if (callback != nullptr) {
128 std::thread([=] {
Tim Zimmermann428bd3e2022-01-31 12:01:42 +0100129 LOG(DEBUG) << "Starting perform on another thread";
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100130 usleep(ms * 1000);
Tim Zimmermann428bd3e2022-01-31 12:01:42 +0100131 LOG(DEBUG) << "Notifying perform complete";
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100132 callback->onComplete();
133 }).detach();
134 }
135
136 *_aidl_return = ms;
137 return status;
138}
139
140ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
Tim Zimmermannc48c38d2023-03-12 12:53:51 +0100141 *_aidl_return = { Effect::CLICK, Effect::TICK };
142
143 if (mHasTimedOutEffect) {
144 for (const auto& effect : CP_TRIGGER_EFFECTS) {
145 _aidl_return->push_back(effect.first);
146 }
147 }
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100148 return ndk::ScopedAStatus::ok();
149}
150
151ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
152 uint32_t intensity;
153
SamarV-12131d105a2023-01-25 16:00:10 +0530154 if (amplitude <= 0.0f || amplitude > 1.0f) {
155 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100156 }
157
SamarV-12131d105a2023-01-25 16:00:10 +0530158 LOG(DEBUG) << "Setting amplitude: " << amplitude;
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100159
SamarV-12131d105a2023-01-25 16:00:10 +0530160 intensity = amplitude * INTENSITY_MAX;
Tim Zimmermann36977e22022-04-15 10:04:25 +0200161
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100162 LOG(DEBUG) << "Setting intensity: " << intensity;
163
164 if (mHasTimedOutIntensity) {
165 return writeNode(VIBRATOR_INTENSITY_PATH, intensity);
166 }
167
168 return ndk::ScopedAStatus::ok();
169}
170
171ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
172 if (mEnabled) {
173 LOG(WARNING) << "Setting external control while the vibrator is enabled is "
174 "unsupported!";
175 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
176 }
177
178 LOG(INFO) << "ExternalControl: " << mExternalControl << " -> " << enabled;
179 mExternalControl = enabled;
180 return ndk::ScopedAStatus::ok();
181}
182
183ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* /*_aidl_return*/) {
184 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
185}
186
187ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* /*_aidl_return*/) {
188 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
189}
190
191ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* /*_aidl_return*/) {
192 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
193}
194
195ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive /*primitive*/, int32_t* /*_aidl_return*/) {
196 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
197}
198
199ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& /*composite*/, const std::shared_ptr<IVibratorCallback>& /*callback*/) {
200 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
201}
202
203ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>* /*_aidl_return*/) {
204 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
205}
206
207ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t /*id*/, Effect /*effect*/, EffectStrength /*strength*/) {
208 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
209}
210
211ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t /*id*/) {
212 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
213}
214
215ndk::ScopedAStatus Vibrator::getResonantFrequency(float* /*_aidl_return*/) {
216 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
217}
218
219ndk::ScopedAStatus Vibrator::getQFactor(float* /*_aidl_return*/) {
220 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
221}
222
223ndk::ScopedAStatus Vibrator::getFrequencyResolution(float* /*_aidl_return*/) {
224 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
225}
226
227ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float* /*_aidl_return*/) {
228 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
229}
230
231ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float>* /*_aidl_return*/) {
232 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
233}
234
235ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t* /*_aidl_return*/) {
236 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
237}
238
239ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t* /*_aidl_return*/) {
240 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
241}
242
243ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking>* /*_aidl_return*/) {
244 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
245}
246
247ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle>& /*composite*/, const std::shared_ptr<IVibratorCallback>& /*callback*/) {
248 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
249}
250
251ndk::ScopedAStatus Vibrator::activate(uint32_t timeoutMs) {
252 std::lock_guard<std::mutex> lock{mMutex};
253 if (!mIsTimedOutVibrator) {
254 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
255 }
256
257 return writeNode(VIBRATOR_TIMEOUT_PATH, timeoutMs);
258}
259
SamarV-12131d105a2023-01-25 16:00:10 +0530260float Vibrator::strengthToAmplitude(EffectStrength strength, ndk::ScopedAStatus* status) {
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100261 *status = ndk::ScopedAStatus::ok();
262
263 switch (strength) {
264 case EffectStrength::LIGHT:
SamarV-12131d105a2023-01-25 16:00:10 +0530265 return AMPLITUDE_LIGHT;
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100266 case EffectStrength::MEDIUM:
SamarV-12131d105a2023-01-25 16:00:10 +0530267 return AMPLITUDE_MEDIUM;
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100268 case EffectStrength::STRONG:
SamarV-12131d105a2023-01-25 16:00:10 +0530269 return AMPLITUDE_STRONG;
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100270 }
271
272 *status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
273 return 0;
274}
275
276uint32_t Vibrator::effectToMs(Effect effect, ndk::ScopedAStatus* status) {
277 *status = ndk::ScopedAStatus::ok();
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100278 switch (effect) {
279 case Effect::CLICK:
Tim Zimmermann428bd3e2022-01-31 12:01:42 +0100280 return 10;
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100281 case Effect::TICK:
Tim Zimmermann428bd3e2022-01-31 12:01:42 +0100282 return 5;
Tim Zimmermannc48c38d2023-03-12 12:53:51 +0100283 default:
284 break;
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100285 }
Tim Zimmermann1bc99f52021-11-23 20:45:19 +0100286 *status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
287 return 0;
288}
289
290} // namespace vibrator
291} // namespace hardware
292} // namespace android
293} // namespace aidl