Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 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 | #define LOG_TAG "VibratorService" |
| 18 | |
| 19 | #include <log/log.h> |
| 20 | |
| 21 | #include "Vibrator.h" |
| 22 | |
| 23 | namespace android { |
| 24 | namespace hardware { |
| 25 | namespace vibrator { |
Harpreet \"Eli\" Sangha | 714220e | 2019-09-27 19:01:25 +0900 | [diff] [blame] | 26 | namespace V1_4 { |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 27 | namespace implementation { |
| 28 | |
| 29 | static constexpr uint32_t MS_PER_S = 1000; |
| 30 | static constexpr uint32_t NS_PER_MS = 1000000; |
| 31 | |
| 32 | Vibrator::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 | |
| 46 | Return<Status> Vibrator::on(uint32_t timeoutMs) { |
| 47 | return activate(timeoutMs); |
| 48 | } |
| 49 | |
| 50 | Return<Status> Vibrator::off() { |
| 51 | return activate(0); |
| 52 | } |
| 53 | |
| 54 | Return<bool> Vibrator::supportsAmplitudeControl() { |
| 55 | return true; |
| 56 | } |
| 57 | |
| 58 | Return<Status> Vibrator::setAmplitude(uint8_t amplitude) { |
Harpreet "Eli" Sangha | 15d5202 | 2019-04-10 16:38:12 +0900 | [diff] [blame] | 59 | if (!amplitude) { |
| 60 | return Status::BAD_VALUE; |
| 61 | } |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 62 | ALOGI("Amplitude: %u -> %u\n", mAmplitude, amplitude); |
| 63 | mAmplitude = amplitude; |
| 64 | return Status::OK; |
| 65 | } |
| 66 | |
| 67 | Return<void> Vibrator::perform(V1_0::Effect effect, EffectStrength strength, perform_cb _hidl_cb) { |
Harpreet "Eli" Sangha | 15d5202 | 2019-04-10 16:38:12 +0900 | [diff] [blame] | 68 | return perform<decltype(effect)>(effect, strength, _hidl_cb); |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | // Methods from ::android::hardware::vibrator::V1_1::IVibrator follow. |
| 72 | |
| 73 | Return<void> Vibrator::perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength, |
| 74 | perform_cb _hidl_cb) { |
Harpreet "Eli" Sangha | 15d5202 | 2019-04-10 16:38:12 +0900 | [diff] [blame] | 75 | return perform<decltype(effect)>(effect, strength, _hidl_cb); |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | // Methods from ::android::hardware::vibrator::V1_2::IVibrator follow. |
| 79 | |
Michael Wright | a4c94fd | 2019-03-21 20:48:34 +0000 | [diff] [blame] | 80 | Return<void> Vibrator::perform_1_2(V1_2::Effect effect, EffectStrength strength, |
| 81 | perform_cb _hidl_cb) { |
Harpreet "Eli" Sangha | 15d5202 | 2019-04-10 16:38:12 +0900 | [diff] [blame] | 82 | return perform<decltype(effect)>(effect, strength, _hidl_cb); |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | // Methods from ::android::hardware::vibrator::V1_3::IVibrator follow. |
| 86 | |
| 87 | Return<bool> Vibrator::supportsExternalControl() { |
| 88 | return true; |
| 89 | } |
| 90 | |
| 91 | Return<Status> Vibrator::setExternalControl(bool enabled) { |
| 92 | if (mEnabled) { |
| 93 | ALOGW("Setting external control while the vibrator is enabled is unsupported!"); |
| 94 | return Status::UNSUPPORTED_OPERATION; |
| 95 | } else { |
| 96 | ALOGI("ExternalControl: %s -> %s\n", mExternalControl ? "true" : "false", |
| 97 | enabled ? "true" : "false"); |
| 98 | mExternalControl = enabled; |
| 99 | return Status::OK; |
| 100 | } |
| 101 | } |
| 102 | |
Harpreet \"Eli\" Sangha | 714220e | 2019-09-27 19:01:25 +0900 | [diff] [blame] | 103 | Return<void> Vibrator::perform_1_3(V1_3::Effect effect, EffectStrength strength, |
| 104 | perform_cb _hidl_cb) { |
| 105 | return perform<decltype(effect)>(effect, strength, _hidl_cb); |
| 106 | } |
| 107 | |
| 108 | // Methods from ::android::hardware::vibrator::V1_4::IVibrator follow. |
| 109 | |
| 110 | Return<hidl_bitfield<Capabilities>> Vibrator::getCapabilities() { |
| 111 | return Capabilities::ON_COMPLETION_CALLBACK | Capabilities::PERFORM_COMPLETION_CALLBACK; |
| 112 | } |
| 113 | |
| 114 | Return<Status> Vibrator::on_1_4(uint32_t timeoutMs, const sp<IVibratorCallback>& callback) { |
| 115 | mCallback = callback; |
| 116 | return on(timeoutMs); |
| 117 | } |
| 118 | |
| 119 | Return<void> Vibrator::perform_1_4(V1_3::Effect effect, EffectStrength strength, |
| 120 | const sp<IVibratorCallback>& callback, perform_cb _hidl_cb) { |
| 121 | mCallback = callback; |
Harpreet "Eli" Sangha | 15d5202 | 2019-04-10 16:38:12 +0900 | [diff] [blame] | 122 | return perform<decltype(effect)>(effect, strength, _hidl_cb); |
| 123 | } |
| 124 | |
| 125 | // Private methods follow. |
| 126 | |
| 127 | Return<void> Vibrator::perform(Effect effect, EffectStrength strength, perform_cb _hidl_cb) { |
Michael Wright | a4c94fd | 2019-03-21 20:48:34 +0000 | [diff] [blame] | 128 | uint8_t amplitude; |
| 129 | uint32_t ms; |
Harpreet "Eli" Sangha | 79755bc | 2019-03-25 16:42:28 +0900 | [diff] [blame] | 130 | Status status = Status::OK; |
Michael Wright | a4c94fd | 2019-03-21 20:48:34 +0000 | [diff] [blame] | 131 | |
Harpreet "Eli" Sangha | a244321 | 2019-03-25 14:08:59 +0900 | [diff] [blame] | 132 | ALOGI("Perform: Effect %s\n", effectToName(effect).c_str()); |
Michael Wright | a4c94fd | 2019-03-21 20:48:34 +0000 | [diff] [blame] | 133 | |
Harpreet "Eli" Sangha | 79755bc | 2019-03-25 16:42:28 +0900 | [diff] [blame] | 134 | amplitude = strengthToAmplitude(strength, &status); |
| 135 | if (status != Status::OK) { |
| 136 | _hidl_cb(status, 0); |
| 137 | return Void(); |
| 138 | } |
Michael Wright | a4c94fd | 2019-03-21 20:48:34 +0000 | [diff] [blame] | 139 | setAmplitude(amplitude); |
| 140 | |
Harpreet "Eli" Sangha | 79755bc | 2019-03-25 16:42:28 +0900 | [diff] [blame] | 141 | ms = effectToMs(effect, &status); |
| 142 | if (status != Status::OK) { |
| 143 | _hidl_cb(status, 0); |
| 144 | return Void(); |
| 145 | } |
Michael Wright | a4c94fd | 2019-03-21 20:48:34 +0000 | [diff] [blame] | 146 | status = activate(ms); |
| 147 | |
| 148 | _hidl_cb(status, ms); |
| 149 | |
| 150 | return Void(); |
| 151 | } |
| 152 | |
Harpreet "Eli" Sangha | 15d5202 | 2019-04-10 16:38:12 +0900 | [diff] [blame] | 153 | template <typename T> |
| 154 | Return<void> Vibrator::perform(T effect, EffectStrength strength, perform_cb _hidl_cb) { |
| 155 | auto validRange = hidl_enum_range<T>(); |
| 156 | if (effect < *validRange.begin() || effect > *std::prev(validRange.end())) { |
| 157 | _hidl_cb(Status::UNSUPPORTED_OPERATION, 0); |
| 158 | return Void(); |
| 159 | } |
| 160 | return perform(static_cast<Effect>(effect), strength, _hidl_cb); |
| 161 | } |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 162 | |
| 163 | Status Vibrator::enable(bool enabled) { |
| 164 | if (mExternalControl) { |
| 165 | ALOGW("Enabling/disabling while the vibrator is externally controlled is unsupported!"); |
| 166 | return Status::UNSUPPORTED_OPERATION; |
| 167 | } else { |
| 168 | ALOGI("Enabled: %s -> %s\n", mEnabled ? "true" : "false", enabled ? "true" : "false"); |
Harpreet \"Eli\" Sangha | 714220e | 2019-09-27 19:01:25 +0900 | [diff] [blame] | 169 | if (mEnabled && !enabled) { |
| 170 | if (auto callback = mCallback) { |
| 171 | mCallback = nullptr; |
| 172 | if (auto ret = callback->onComplete(); !ret.isOk()) { |
| 173 | ALOGE("Failed completion callback: %s", ret.description().c_str()); |
| 174 | } |
| 175 | } |
| 176 | } |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 177 | mEnabled = enabled; |
| 178 | return Status::OK; |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | Status Vibrator::activate(uint32_t ms) { |
| 183 | std::lock_guard<std::mutex> lock{mMutex}; |
| 184 | Status status = Status::OK; |
| 185 | |
| 186 | if (ms > 0) { |
| 187 | status = enable(true); |
| 188 | if (status != Status::OK) { |
| 189 | return status; |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | itimerspec ts{}; |
| 194 | ts.it_value.tv_sec = ms / MS_PER_S; |
| 195 | ts.it_value.tv_nsec = ms % MS_PER_S * NS_PER_MS; |
| 196 | |
| 197 | if (timer_settime(mTimer, 0, &ts, nullptr) < 0) { |
| 198 | ALOGE("Can not set timer!"); |
| 199 | status = Status::UNKNOWN_ERROR; |
| 200 | } |
| 201 | |
| 202 | if ((status != Status::OK) || !ms) { |
| 203 | Status _status; |
| 204 | |
| 205 | _status = enable(false); |
| 206 | |
| 207 | if (status == Status::OK) { |
| 208 | status = _status; |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | return status; |
| 213 | } |
| 214 | |
| 215 | void Vibrator::timeout() { |
| 216 | std::lock_guard<std::mutex> lock{mMutex}; |
| 217 | itimerspec ts{}; |
| 218 | |
| 219 | if (timer_gettime(mTimer, &ts) < 0) { |
| 220 | ALOGE("Can not read timer!"); |
| 221 | } |
| 222 | |
| 223 | if (ts.it_value.tv_sec == 0 && ts.it_value.tv_nsec == 0) { |
| 224 | enable(false); |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | void Vibrator::timerCallback(union sigval sigval) { |
| 229 | static_cast<Vibrator*>(sigval.sival_ptr)->timeout(); |
| 230 | } |
| 231 | |
Harpreet "Eli" Sangha | a244321 | 2019-03-25 14:08:59 +0900 | [diff] [blame] | 232 | const std::string Vibrator::effectToName(Effect effect) { |
| 233 | return toString(effect); |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 234 | } |
| 235 | |
Harpreet "Eli" Sangha | 79755bc | 2019-03-25 16:42:28 +0900 | [diff] [blame] | 236 | uint32_t Vibrator::effectToMs(Effect effect, Status* status) { |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 237 | switch (effect) { |
| 238 | case Effect::CLICK: |
| 239 | return 10; |
| 240 | case Effect::DOUBLE_CLICK: |
| 241 | return 15; |
| 242 | case Effect::TICK: |
Michael Wright | a4c94fd | 2019-03-21 20:48:34 +0000 | [diff] [blame] | 243 | case Effect::TEXTURE_TICK: |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 244 | return 5; |
| 245 | case Effect::THUD: |
| 246 | return 5; |
| 247 | case Effect::POP: |
| 248 | return 5; |
| 249 | case Effect::HEAVY_CLICK: |
| 250 | return 10; |
| 251 | case Effect::RINGTONE_1: |
| 252 | return 30000; |
| 253 | case Effect::RINGTONE_2: |
| 254 | return 30000; |
| 255 | case Effect::RINGTONE_3: |
| 256 | return 30000; |
| 257 | case Effect::RINGTONE_4: |
| 258 | return 30000; |
| 259 | case Effect::RINGTONE_5: |
| 260 | return 30000; |
| 261 | case Effect::RINGTONE_6: |
| 262 | return 30000; |
| 263 | case Effect::RINGTONE_7: |
| 264 | return 30000; |
| 265 | case Effect::RINGTONE_8: |
| 266 | return 30000; |
| 267 | case Effect::RINGTONE_9: |
| 268 | return 30000; |
| 269 | case Effect::RINGTONE_10: |
| 270 | return 30000; |
| 271 | case Effect::RINGTONE_11: |
| 272 | return 30000; |
| 273 | case Effect::RINGTONE_12: |
| 274 | return 30000; |
| 275 | case Effect::RINGTONE_13: |
| 276 | return 30000; |
| 277 | case Effect::RINGTONE_14: |
| 278 | return 30000; |
| 279 | case Effect::RINGTONE_15: |
| 280 | return 30000; |
| 281 | } |
Harpreet "Eli" Sangha | 79755bc | 2019-03-25 16:42:28 +0900 | [diff] [blame] | 282 | *status = Status::UNSUPPORTED_OPERATION; |
| 283 | return 0; |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 284 | } |
| 285 | |
Harpreet "Eli" Sangha | 79755bc | 2019-03-25 16:42:28 +0900 | [diff] [blame] | 286 | uint8_t Vibrator::strengthToAmplitude(EffectStrength strength, Status* status) { |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 287 | switch (strength) { |
| 288 | case EffectStrength::LIGHT: |
| 289 | return 128; |
| 290 | case EffectStrength::MEDIUM: |
| 291 | return 192; |
| 292 | case EffectStrength::STRONG: |
| 293 | return 255; |
| 294 | } |
Harpreet "Eli" Sangha | 79755bc | 2019-03-25 16:42:28 +0900 | [diff] [blame] | 295 | *status = Status::UNSUPPORTED_OPERATION; |
| 296 | return 0; |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 297 | } |
| 298 | |
| 299 | } // namespace implementation |
Harpreet \"Eli\" Sangha | 714220e | 2019-09-27 19:01:25 +0900 | [diff] [blame] | 300 | } // namespace V1_4 |
Harpreet "Eli" Sangha | e863124 | 2019-01-31 15:43:36 +0900 | [diff] [blame] | 301 | } // namespace vibrator |
| 302 | } // namespace hardware |
| 303 | } // namespace android |