blob: 0cb37e6a365a118a97044a846a0b907965f6d31b [file] [log] [blame]
Harpreet "Eli" Sanghae8631242019-01-31 15:43:36 +09001/*
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#define LOG_TAG "VibratorService"
18
19#include <log/log.h>
20
21#include "Vibrator.h"
22
23namespace android {
24namespace hardware {
25namespace vibrator {
26namespace V1_3 {
27namespace implementation {
28
29static constexpr uint32_t MS_PER_S = 1000;
30static constexpr uint32_t NS_PER_MS = 1000000;
31
32Vibrator::Vibrator() {
33 sigevent se{};
34 se.sigev_notify = SIGEV_THREAD;
35 se.sigev_value.sival_ptr = this;
36 se.sigev_notify_function = timerCallback;
37 se.sigev_notify_attributes = nullptr;
38
39 if (timer_create(CLOCK_REALTIME, &se, &mTimer) < 0) {
40 ALOGE("Can not create timer!%s", strerror(errno));
41 }
42}
43
44// Methods from ::android::hardware::vibrator::V1_0::IVibrator follow.
45
46Return<Status> Vibrator::on(uint32_t timeoutMs) {
47 return activate(timeoutMs);
48}
49
50Return<Status> Vibrator::off() {
51 return activate(0);
52}
53
54Return<bool> Vibrator::supportsAmplitudeControl() {
55 return true;
56}
57
58Return<Status> Vibrator::setAmplitude(uint8_t amplitude) {
59 ALOGI("Amplitude: %u -> %u\n", mAmplitude, amplitude);
60 mAmplitude = amplitude;
61 return Status::OK;
62}
63
64Return<void> Vibrator::perform(V1_0::Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
65 return perform_1_1(static_cast<V1_1::Effect_1_1>(effect), strength, _hidl_cb);
66}
67
68// Methods from ::android::hardware::vibrator::V1_1::IVibrator follow.
69
70Return<void> Vibrator::perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength,
71 perform_cb _hidl_cb) {
72 return perform_1_2(static_cast<V1_2::Effect>(effect), strength, _hidl_cb);
73}
74
75// Methods from ::android::hardware::vibrator::V1_2::IVibrator follow.
76
Michael Wrighta4c94fd2019-03-21 20:48:34 +000077Return<void> Vibrator::perform_1_2(V1_2::Effect effect, EffectStrength strength,
78 perform_cb _hidl_cb) {
79 return perform_1_3(static_cast<V1_3::Effect>(effect), strength, _hidl_cb);
Harpreet "Eli" Sanghae8631242019-01-31 15:43:36 +090080}
81
82// Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
83
84Return<bool> Vibrator::supportsExternalControl() {
85 return true;
86}
87
88Return<Status> Vibrator::setExternalControl(bool enabled) {
89 if (mEnabled) {
90 ALOGW("Setting external control while the vibrator is enabled is unsupported!");
91 return Status::UNSUPPORTED_OPERATION;
92 } else {
93 ALOGI("ExternalControl: %s -> %s\n", mExternalControl ? "true" : "false",
94 enabled ? "true" : "false");
95 mExternalControl = enabled;
96 return Status::OK;
97 }
98}
99
Michael Wrighta4c94fd2019-03-21 20:48:34 +0000100Return<void> Vibrator::perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
101 uint8_t amplitude;
102 uint32_t ms;
Harpreet "Eli" Sangha79755bc2019-03-25 16:42:28 +0900103 Status status = Status::OK;
Michael Wrighta4c94fd2019-03-21 20:48:34 +0000104
Harpreet "Eli" Sanghaa2443212019-03-25 14:08:59 +0900105 ALOGI("Perform: Effect %s\n", effectToName(effect).c_str());
Michael Wrighta4c94fd2019-03-21 20:48:34 +0000106
Harpreet "Eli" Sangha79755bc2019-03-25 16:42:28 +0900107 amplitude = strengthToAmplitude(strength, &status);
108 if (status != Status::OK) {
109 _hidl_cb(status, 0);
110 return Void();
111 }
Michael Wrighta4c94fd2019-03-21 20:48:34 +0000112 setAmplitude(amplitude);
113
Harpreet "Eli" Sangha79755bc2019-03-25 16:42:28 +0900114 ms = effectToMs(effect, &status);
115 if (status != Status::OK) {
116 _hidl_cb(status, 0);
117 return Void();
118 }
Michael Wrighta4c94fd2019-03-21 20:48:34 +0000119 status = activate(ms);
120
121 _hidl_cb(status, ms);
122
123 return Void();
124}
125
Harpreet "Eli" Sanghae8631242019-01-31 15:43:36 +0900126// Private methods follow.
127
128Status Vibrator::enable(bool enabled) {
129 if (mExternalControl) {
130 ALOGW("Enabling/disabling while the vibrator is externally controlled is unsupported!");
131 return Status::UNSUPPORTED_OPERATION;
132 } else {
133 ALOGI("Enabled: %s -> %s\n", mEnabled ? "true" : "false", enabled ? "true" : "false");
134 mEnabled = enabled;
135 return Status::OK;
136 }
137}
138
139Status Vibrator::activate(uint32_t ms) {
140 std::lock_guard<std::mutex> lock{mMutex};
141 Status status = Status::OK;
142
143 if (ms > 0) {
144 status = enable(true);
145 if (status != Status::OK) {
146 return status;
147 }
148 }
149
150 itimerspec ts{};
151 ts.it_value.tv_sec = ms / MS_PER_S;
152 ts.it_value.tv_nsec = ms % MS_PER_S * NS_PER_MS;
153
154 if (timer_settime(mTimer, 0, &ts, nullptr) < 0) {
155 ALOGE("Can not set timer!");
156 status = Status::UNKNOWN_ERROR;
157 }
158
159 if ((status != Status::OK) || !ms) {
160 Status _status;
161
162 _status = enable(false);
163
164 if (status == Status::OK) {
165 status = _status;
166 }
167 }
168
169 return status;
170}
171
172void Vibrator::timeout() {
173 std::lock_guard<std::mutex> lock{mMutex};
174 itimerspec ts{};
175
176 if (timer_gettime(mTimer, &ts) < 0) {
177 ALOGE("Can not read timer!");
178 }
179
180 if (ts.it_value.tv_sec == 0 && ts.it_value.tv_nsec == 0) {
181 enable(false);
182 }
183}
184
185void Vibrator::timerCallback(union sigval sigval) {
186 static_cast<Vibrator*>(sigval.sival_ptr)->timeout();
187}
188
Harpreet "Eli" Sanghaa2443212019-03-25 14:08:59 +0900189const std::string Vibrator::effectToName(Effect effect) {
190 return toString(effect);
Harpreet "Eli" Sanghae8631242019-01-31 15:43:36 +0900191}
192
Harpreet "Eli" Sangha79755bc2019-03-25 16:42:28 +0900193uint32_t Vibrator::effectToMs(Effect effect, Status* status) {
Harpreet "Eli" Sanghae8631242019-01-31 15:43:36 +0900194 switch (effect) {
195 case Effect::CLICK:
196 return 10;
197 case Effect::DOUBLE_CLICK:
198 return 15;
199 case Effect::TICK:
Michael Wrighta4c94fd2019-03-21 20:48:34 +0000200 case Effect::TEXTURE_TICK:
Harpreet "Eli" Sanghae8631242019-01-31 15:43:36 +0900201 return 5;
202 case Effect::THUD:
203 return 5;
204 case Effect::POP:
205 return 5;
206 case Effect::HEAVY_CLICK:
207 return 10;
208 case Effect::RINGTONE_1:
209 return 30000;
210 case Effect::RINGTONE_2:
211 return 30000;
212 case Effect::RINGTONE_3:
213 return 30000;
214 case Effect::RINGTONE_4:
215 return 30000;
216 case Effect::RINGTONE_5:
217 return 30000;
218 case Effect::RINGTONE_6:
219 return 30000;
220 case Effect::RINGTONE_7:
221 return 30000;
222 case Effect::RINGTONE_8:
223 return 30000;
224 case Effect::RINGTONE_9:
225 return 30000;
226 case Effect::RINGTONE_10:
227 return 30000;
228 case Effect::RINGTONE_11:
229 return 30000;
230 case Effect::RINGTONE_12:
231 return 30000;
232 case Effect::RINGTONE_13:
233 return 30000;
234 case Effect::RINGTONE_14:
235 return 30000;
236 case Effect::RINGTONE_15:
237 return 30000;
238 }
Harpreet "Eli" Sangha79755bc2019-03-25 16:42:28 +0900239 *status = Status::UNSUPPORTED_OPERATION;
240 return 0;
Harpreet "Eli" Sanghae8631242019-01-31 15:43:36 +0900241}
242
Harpreet "Eli" Sangha79755bc2019-03-25 16:42:28 +0900243uint8_t Vibrator::strengthToAmplitude(EffectStrength strength, Status* status) {
Harpreet "Eli" Sanghae8631242019-01-31 15:43:36 +0900244 switch (strength) {
245 case EffectStrength::LIGHT:
246 return 128;
247 case EffectStrength::MEDIUM:
248 return 192;
249 case EffectStrength::STRONG:
250 return 255;
251 }
Harpreet "Eli" Sangha79755bc2019-03-25 16:42:28 +0900252 *status = Status::UNSUPPORTED_OPERATION;
253 return 0;
Harpreet "Eli" Sanghae8631242019-01-31 15:43:36 +0900254}
255
256} // namespace implementation
257} // namespace V1_3
258} // namespace vibrator
259} // namespace hardware
260} // namespace android