blob: ec7e114afcdd681b77acaf76b8a268529382049d [file] [log] [blame]
Fenglin Wua7baae42020-06-30 15:59:56 +08001/*
Jishnu Prakashfc2ed842021-01-05 13:41:04 +05302 * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
Fenglin Wua7baae42020-06-30 15:59:56 +08003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#define LOG_TAG "vendor.qti.vibrator"
31
32#include <dirent.h>
33#include <inttypes.h>
34#include <linux/input.h>
35#include <log/log.h>
36#include <string.h>
37#include <sys/ioctl.h>
38#include <thread>
39
40#include "include/Vibrator.h"
41#ifdef USE_EFFECT_STREAM
42#include "effect.h"
43#endif
44
45extern "C" {
46#include "libsoc_helper.h"
47}
48namespace aidl {
49namespace android {
50namespace hardware {
51namespace vibrator {
52
53#define STRONG_MAGNITUDE 0x7fff
54#define MEDIUM_MAGNITUDE 0x5fff
55#define LIGHT_MAGNITUDE 0x3fff
56#define INVALID_VALUE -1
Fenglin Wuc8f31f12021-04-16 08:54:40 +080057#define CUSTOM_DATA_LEN 3
58#define NAME_BUF_SIZE 32
Fenglin Wua7baae42020-06-30 15:59:56 +080059
YU Shixianbc9ed8d2023-03-03 18:27:49 +080060#define VIB_LED 0x01
61#define VIB_AW 0x02
62
63#define VIB_ALL (VIB_LED|VIB_AW)
64
Fenglin Wua7baae42020-06-30 15:59:56 +080065#define test_bit(bit, array) ((array)[(bit)/8] & (1<<((bit)%8)))
66
Kiran Gundab4935072020-07-19 19:30:14 +053067static const char LED_DEVICE[] = "/sys/class/leds/vibrator";
YU Shixianbc9ed8d2023-03-03 18:27:49 +080068static const char AW_DEVICE[] = "/sys/class/leds/vibrator_1";
Fenglin Wua7baae42020-06-30 15:59:56 +080069InputFFDevice::InputFFDevice()
70{
71 DIR *dp;
72 struct dirent *dir;
73 uint8_t ffBitmask[FF_CNT / 8];
74 char devicename[PATH_MAX];
75 const char *INPUT_DIR = "/dev/input/";
Fenglin Wuc8f31f12021-04-16 08:54:40 +080076 char name[NAME_BUF_SIZE];
Fenglin Wua7baae42020-06-30 15:59:56 +080077 int fd, ret;
78 soc_info_v0_1_t soc = {MSM_CPU_UNKNOWN};
79
80 mVibraFd = INVALID_VALUE;
81 mSupportGain = false;
82 mSupportEffects = false;
83 mSupportExternalControl = false;
84 mCurrAppId = INVALID_VALUE;
85 mCurrMagnitude = 0x7fff;
86 mInExternalControl = false;
87
88 dp = opendir(INPUT_DIR);
89 if (!dp) {
90 ALOGE("open %s failed, errno = %d", INPUT_DIR, errno);
91 return;
92 }
93
94 memset(ffBitmask, 0, sizeof(ffBitmask));
95 while ((dir = readdir(dp)) != NULL){
96 if (dir->d_name[0] == '.' &&
97 (dir->d_name[1] == '\0' ||
98 (dir->d_name[1] == '.' && dir->d_name[2] == '\0')))
99 continue;
100
101 snprintf(devicename, PATH_MAX, "%s%s", INPUT_DIR, dir->d_name);
102 fd = TEMP_FAILURE_RETRY(open(devicename, O_RDWR));
103 if (fd < 0) {
104 ALOGE("open %s failed, errno = %d", devicename, errno);
105 continue;
106 }
107
Fenglin Wuc8f31f12021-04-16 08:54:40 +0800108 ret = TEMP_FAILURE_RETRY(ioctl(fd, EVIOCGNAME(sizeof(name)), name));
109 if (ret == -1) {
110 ALOGE("get input device name %s failed, errno = %d\n", devicename, errno);
111 close(fd);
112 continue;
113 }
114
115 if (strcmp(name, "qcom-hv-haptics") && strcmp(name, "qti-haptics")) {
116 ALOGD("not a qcom/qti haptics device\n");
117 close(fd);
118 continue;
119 }
120
121 ALOGI("%s is detected at %s\n", name, devicename);
Fenglin Wua7baae42020-06-30 15:59:56 +0800122 ret = TEMP_FAILURE_RETRY(ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffBitmask)), ffBitmask));
123 if (ret == -1) {
124 ALOGE("ioctl failed, errno = %d", errno);
125 close(fd);
126 continue;
127 }
128
129 if (test_bit(FF_CONSTANT, ffBitmask) ||
130 test_bit(FF_PERIODIC, ffBitmask)) {
131 mVibraFd = fd;
132 if (test_bit(FF_CUSTOM, ffBitmask))
133 mSupportEffects = true;
134 if (test_bit(FF_GAIN, ffBitmask))
135 mSupportGain = true;
136
137 get_soc_info(&soc);
138 ALOGD("msm CPU SoC ID: %d\n", soc.msm_cpu);
139 switch (soc.msm_cpu) {
140 case MSM_CPU_LAHAINA:
141 case APQ_CPU_LAHAINA:
142 case MSM_CPU_SHIMA:
Subbaraman Narayanamurthy534d2712020-12-15 14:49:00 -0800143 case MSM_CPU_SM8325:
144 case APQ_CPU_SM8325P:
Jishnu Prakashfc2ed842021-01-05 13:41:04 +0530145 case MSM_CPU_YUPIK:
Fenglin Wua7baae42020-06-30 15:59:56 +0800146 mSupportExternalControl = true;
147 break;
148 default:
149 mSupportExternalControl = false;
150 break;
151 }
152 break;
153 }
154
155 close(fd);
156 }
157
158 closedir(dp);
159}
160
161/** Play vibration
162 *
163 * @param effectId: ID of the predefined effect will be played. If effectId is valid
164 * (non-negative value), the timeoutMs value will be ignored, and the
165 * real playing length will be set in param@playLengtMs and returned
166 * to VibratorService. If effectId is invalid, value in param@timeoutMs
167 * will be used as the play length for playing a constant effect.
168 * @param timeoutMs: playing length, non-zero means playing, zero means stop playing.
169 * @param playLengthMs: the playing length in ms unit which will be returned to
170 * VibratorService if the request is playing a predefined effect.
171 * The custom_data in periodic is reused for returning the playLengthMs
172 * from kernel space to userspace if the pattern is defined in kernel
173 * driver. It's been defined with following format:
174 * <effect-ID, play-time-in-seconds, play-time-in-milliseconds>.
175 * The effect-ID is used for passing down the predefined effect to
176 * kernel driver, and the rest two parameters are used for returning
177 * back the real playing length from kernel driver.
178 */
179int InputFFDevice::play(int effectId, uint32_t timeoutMs, long *playLengthMs) {
180 struct ff_effect effect;
181 struct input_event play;
182 int16_t data[CUSTOM_DATA_LEN] = {0, 0, 0};
183 int ret;
184#ifdef USE_EFFECT_STREAM
185 const struct effect_stream *stream;
186#endif
187
188 /* For QMAA compliance, return OK even if vibrator device doesn't exist */
189 if (mVibraFd == INVALID_VALUE) {
190 if (playLengthMs != NULL)
191 *playLengthMs = 0;
192 return 0;
193 }
194
195 if (timeoutMs != 0) {
196 if (mCurrAppId != INVALID_VALUE) {
197 ret = TEMP_FAILURE_RETRY(ioctl(mVibraFd, EVIOCRMFF, mCurrAppId));
198 if (ret == -1) {
199 ALOGE("ioctl EVIOCRMFF failed, errno = %d", -errno);
200 goto errout;
201 }
202 mCurrAppId = INVALID_VALUE;
203 }
204
205 memset(&effect, 0, sizeof(effect));
206 if (effectId != INVALID_VALUE) {
207 data[0] = effectId;
208 effect.type = FF_PERIODIC;
209 effect.u.periodic.waveform = FF_CUSTOM;
210 effect.u.periodic.magnitude = mCurrMagnitude;
211 effect.u.periodic.custom_data = data;
212 effect.u.periodic.custom_len = sizeof(int16_t) * CUSTOM_DATA_LEN;
213#ifdef USE_EFFECT_STREAM
214 stream = get_effect_stream(effectId);
215 if (stream != NULL) {
216 effect.u.periodic.custom_data = (int16_t *)stream;
217 effect.u.periodic.custom_len = sizeof(*stream);
218 }
219#endif
220 } else {
221 effect.type = FF_CONSTANT;
222 effect.u.constant.level = mCurrMagnitude;
223 effect.replay.length = timeoutMs;
224 }
225
226 effect.id = mCurrAppId;
227 effect.replay.delay = 0;
228
229 ret = TEMP_FAILURE_RETRY(ioctl(mVibraFd, EVIOCSFF, &effect));
230 if (ret == -1) {
231 ALOGE("ioctl EVIOCSFF failed, errno = %d", -errno);
232 goto errout;
233 }
234
235 mCurrAppId = effect.id;
236 if (effectId != INVALID_VALUE && playLengthMs != NULL) {
237 *playLengthMs = data[1] * 1000 + data[2];
238#ifdef USE_EFFECT_STREAM
239 if (stream != NULL && stream->play_rate_hz != 0)
240 *playLengthMs = ((stream->length * 1000) / stream->play_rate_hz) + 1;
241#endif
242 }
243
244 play.value = 1;
245 play.type = EV_FF;
246 play.code = mCurrAppId;
247 play.time.tv_sec = 0;
248 play.time.tv_usec = 0;
249 ret = TEMP_FAILURE_RETRY(write(mVibraFd, (const void*)&play, sizeof(play)));
250 if (ret == -1) {
251 ALOGE("write failed, errno = %d\n", -errno);
252 ret = TEMP_FAILURE_RETRY(ioctl(mVibraFd, EVIOCRMFF, mCurrAppId));
253 if (ret == -1)
254 ALOGE("ioctl EVIOCRMFF failed, errno = %d", -errno);
255 goto errout;
256 }
257 } else if (mCurrAppId != INVALID_VALUE) {
258 ret = TEMP_FAILURE_RETRY(ioctl(mVibraFd, EVIOCRMFF, mCurrAppId));
259 if (ret == -1) {
260 ALOGE("ioctl EVIOCRMFF failed, errno = %d", -errno);
261 goto errout;
262 }
263 mCurrAppId = INVALID_VALUE;
264 }
265 return 0;
266
267errout:
268 mCurrAppId = INVALID_VALUE;
269 return ret;
270}
271
272int InputFFDevice::on(int32_t timeoutMs) {
273 return play(INVALID_VALUE, timeoutMs, NULL);
274}
275
276int InputFFDevice::off() {
277 return play(INVALID_VALUE, 0, NULL);
278}
279
280int InputFFDevice::setAmplitude(uint8_t amplitude) {
281 int tmp, ret;
282 struct input_event ie;
283
284 /* For QMAA compliance, return OK even if vibrator device doesn't exist */
285 if (mVibraFd == INVALID_VALUE)
286 return 0;
287
288 tmp = amplitude * (STRONG_MAGNITUDE - LIGHT_MAGNITUDE) / 255;
289 tmp += LIGHT_MAGNITUDE;
290 ie.type = EV_FF;
291 ie.code = FF_GAIN;
292 ie.value = tmp;
293
294 ret = TEMP_FAILURE_RETRY(write(mVibraFd, &ie, sizeof(ie)));
295 if (ret == -1) {
296 ALOGE("write FF_GAIN failed, errno = %d", -errno);
297 return ret;
298 }
299
300 mCurrMagnitude = tmp;
301 return 0;
302}
303
304int InputFFDevice::playEffect(int effectId, EffectStrength es, long *playLengthMs) {
305 switch (es) {
306 case EffectStrength::LIGHT:
307 mCurrMagnitude = LIGHT_MAGNITUDE;
308 break;
309 case EffectStrength::MEDIUM:
310 mCurrMagnitude = MEDIUM_MAGNITUDE;
311 break;
312 case EffectStrength::STRONG:
313 mCurrMagnitude = STRONG_MAGNITUDE;
314 break;
315 default:
316 return -1;
317 }
318
319 return play(effectId, INVALID_VALUE, playLengthMs);
320}
321
Kiran Gundab4935072020-07-19 19:30:14 +0530322LedVibratorDevice::LedVibratorDevice() {
323 char devicename[PATH_MAX];
324 int fd;
325
326 mDetected = false;
YU Shixianbc9ed8d2023-03-03 18:27:49 +0800327 vibrator_dev = VIB_ALL;
Kiran Gundab4935072020-07-19 19:30:14 +0530328
329 snprintf(devicename, sizeof(devicename), "%s/%s", LED_DEVICE, "activate");
330 fd = TEMP_FAILURE_RETRY(open(devicename, O_RDWR));
331 if (fd < 0) {
332 ALOGE("open %s failed, errno = %d", devicename, errno);
YU Shixianbc9ed8d2023-03-03 18:27:49 +0800333 vibrator_dev &= ~ VIB_LED;
334 // return;
Kiran Gundab4935072020-07-19 19:30:14 +0530335 }
336
YU Shixianbc9ed8d2023-03-03 18:27:49 +0800337 snprintf(devicename, sizeof(devicename), "%s/%s", AW_DEVICE, "activate");
338 fd = TEMP_FAILURE_RETRY(open(devicename, O_RDWR));
339 if (fd < 0) {
340 ALOGE("open %s failed, errno = %d", devicename, errno);
341 vibrator_dev &= ~ VIB_AW;
342 }
343 ALOGI("vibrator device = %d", vibrator_dev);
344 if(!vibrator_dev)
345 return;
346
Kiran Gundab4935072020-07-19 19:30:14 +0530347 mDetected = true;
348}
349
350int LedVibratorDevice::write_value(const char *file, const char *value) {
351 int fd;
352 int ret;
353
354 fd = TEMP_FAILURE_RETRY(open(file, O_WRONLY));
355 if (fd < 0) {
356 ALOGE("open %s failed, errno = %d", file, errno);
357 return -errno;
358 }
359
360 ret = TEMP_FAILURE_RETRY(write(fd, value, strlen(value) + 1));
361 if (ret == -1) {
362 ret = -errno;
363 } else if (ret != strlen(value) + 1) {
364 /* even though EAGAIN is an errno value that could be set
365 by write() in some cases, none of them apply here. So, this return
366 value can be clearly identified when debugging and suggests the
367 caller that it may try to call vibrator_on() again */
368 ret = -EAGAIN;
369 } else {
370 ret = 0;
371 }
372
373 errno = 0;
374 close(fd);
375
376 return ret;
377}
378
379int LedVibratorDevice::on(int32_t timeoutMs) {
380 char file[PATH_MAX];
381 char value[32];
382 int ret;
383
YU Shixianbc9ed8d2023-03-03 18:27:49 +0800384 if(vibrator_dev & VIB_AW)
385 {
386 ALOGI("AwVibrator time = %d ",timeoutMs);
387
388 snprintf(file, sizeof(file), "%s/%s", AW_DEVICE, "activate_mode");
389 ret = write_value(file, "0");
390 if (ret < 0)
391 goto error;
392
YU Shixiane896e902023-03-14 17:56:40 +0800393 if (timeoutMs <= 50) {
394 snprintf(file, sizeof(file), "%s/%s", AW_DEVICE, "seq");
395 ret = write_value(file, "0x00 0x00");
396 if (ret < 0)
397 goto error;
398
399 snprintf(file, sizeof(file), "%s/%s", AW_DEVICE, "seq");
400 ret = write_value(file, "0x00 0x01");
401 if (ret < 0)
402 goto error;
403
404 snprintf(file, sizeof(file), "%s/%s", AW_DEVICE, "loop");
405 ret = write_value(file, "0x00 0x00");
406 if (ret < 0)
407 goto error;
408
409 snprintf(file, sizeof(file), "%s/%s", AW_DEVICE, "duration");
410 snprintf(value, sizeof(value), "%u\n", timeoutMs);
411 ret = write_value(file, value);
412 if (ret < 0)
413 goto error;
414
415 snprintf(file, sizeof(file), "%s/%s", AW_DEVICE, "brightness");
416 ret = write_value(file, "1");
417 if (ret < 0)
418 goto error;
419
420 return 0;
421
422 } else {
YU Shixian11889dd2023-03-06 18:09:29 +0800423 snprintf(file, sizeof(file), "%s/%s", AW_DEVICE, "index");
424 ret = write_value(file, "4");
425 if (ret < 0)
426 goto error;
YU Shixianbc9ed8d2023-03-03 18:27:49 +0800427
428 snprintf(file, sizeof(file), "%s/%s", AW_DEVICE, "duration");
429 snprintf(value, sizeof(value), "%u\n", timeoutMs);
430 ret = write_value(file, value);
431 if (ret < 0)
432 goto error;
433
434 snprintf(file, sizeof(file), "%s/%s", AW_DEVICE, "activate");
435 ret = write_value(file, "1");
436 if (ret < 0)
437 goto error;
438
439 return 0;
YU Shixiane896e902023-03-14 17:56:40 +0800440 }
YU Shixianbc9ed8d2023-03-03 18:27:49 +0800441 }
442
Kiran Gundab4935072020-07-19 19:30:14 +0530443 snprintf(file, sizeof(file), "%s/%s", LED_DEVICE, "state");
444 ret = write_value(file, "1");
445 if (ret < 0)
446 goto error;
447
448 snprintf(file, sizeof(file), "%s/%s", LED_DEVICE, "duration");
449 snprintf(value, sizeof(value), "%u\n", timeoutMs);
450 ret = write_value(file, value);
451 if (ret < 0)
452 goto error;
453
454 snprintf(file, sizeof(file), "%s/%s", LED_DEVICE, "activate");
455 ret = write_value(file, "1");
456 if (ret < 0)
457 goto error;
458
459 return 0;
460
461error:
462 ALOGE("Failed to turn on vibrator ret: %d\n", ret);
463 return ret;
464}
465
466int LedVibratorDevice::off()
467{
468 char file[PATH_MAX];
469 int ret;
YU Shixianbc9ed8d2023-03-03 18:27:49 +0800470 ALOGI("LedVibrator device = %d ",vibrator_dev);
471 if(vibrator_dev & VIB_AW)
472 {
473 snprintf(file, sizeof(file), "%s/%s", AW_DEVICE, "activate");
474 ret = write_value(file, "0");
YU Shixian11889dd2023-03-06 18:09:29 +0800475
YU Shixiane896e902023-03-14 17:56:40 +0800476
477 snprintf(file, sizeof(file), "%s/%s", AW_DEVICE, "brightness");
478 ret = write_value(file, "0");
479 if (ret < 0)
480 return ret;
481
YU Shixian11889dd2023-03-06 18:09:29 +0800482 snprintf(file, sizeof(file), "%s/%s", AW_DEVICE, "index");
483 ret = write_value(file, "1");
484 if (ret < 0)
485 return ret;
486
YU Shixianbc9ed8d2023-03-03 18:27:49 +0800487 return ret;
488 }
Kiran Gundab4935072020-07-19 19:30:14 +0530489
490 snprintf(file, sizeof(file), "%s/%s", LED_DEVICE, "activate");
491 ret = write_value(file, "0");
492 return ret;
493}
494
Fenglin Wua7baae42020-06-30 15:59:56 +0800495ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
496 *_aidl_return = IVibrator::CAP_ON_CALLBACK;
Kiran Gundab4935072020-07-19 19:30:14 +0530497
498 if (ledVib.mDetected) {
499 *_aidl_return |= IVibrator::CAP_PERFORM_CALLBACK;
500 ALOGD("QTI Vibrator reporting capabilities: %d", *_aidl_return);
501 return ndk::ScopedAStatus::ok();
502 }
503
Fenglin Wua7baae42020-06-30 15:59:56 +0800504 if (ff.mSupportGain)
505 *_aidl_return |= IVibrator::CAP_AMPLITUDE_CONTROL;
506 if (ff.mSupportEffects)
507 *_aidl_return |= IVibrator::CAP_PERFORM_CALLBACK;
508 if (ff.mSupportExternalControl)
509 *_aidl_return |= IVibrator::CAP_EXTERNAL_CONTROL;
510
511 ALOGD("QTI Vibrator reporting capabilities: %d", *_aidl_return);
512 return ndk::ScopedAStatus::ok();
513}
514
515ndk::ScopedAStatus Vibrator::off() {
516 int ret;
517
518 ALOGD("QTI Vibrator off");
Kiran Gundab4935072020-07-19 19:30:14 +0530519 if (ledVib.mDetected)
520 ret = ledVib.off();
521 else
522 ret = ff.off();
Fenglin Wua7baae42020-06-30 15:59:56 +0800523 if (ret != 0)
524 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC));
525
526 return ndk::ScopedAStatus::ok();
527}
528
529ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
530 const std::shared_ptr<IVibratorCallback>& callback) {
531 int ret;
532
533 ALOGD("Vibrator on for timeoutMs: %d", timeoutMs);
Kiran Gundab4935072020-07-19 19:30:14 +0530534 if (ledVib.mDetected)
535 ret = ledVib.on(timeoutMs);
536 else
537 ret = ff.on(timeoutMs);
538
Fenglin Wua7baae42020-06-30 15:59:56 +0800539 if (ret != 0)
540 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC));
541
542 if (callback != nullptr) {
543 std::thread([=] {
544 ALOGD("Starting on on another thread");
545 usleep(timeoutMs * 1000);
546 ALOGD("Notifying on complete");
547 if (!callback->onComplete().isOk()) {
548 ALOGE("Failed to call onComplete");
549 }
550 }).detach();
551 }
552
553 return ndk::ScopedAStatus::ok();
554}
555
556ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength es, const std::shared_ptr<IVibratorCallback>& callback, int32_t* _aidl_return) {
557 long playLengthMs;
558 int ret;
559
Kiran Gundab4935072020-07-19 19:30:14 +0530560 if (ledVib.mDetected)
561 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
562
Fenglin Wua7baae42020-06-30 15:59:56 +0800563 ALOGD("Vibrator perform effect %d", effect);
564
Kiran Gunda5fba8112021-09-15 18:36:27 +0530565#ifdef TARGET_SUPPORTS_OFFLOAD
566 if (effect < Effect::CLICK || effect > Effect::RINGTONE_15)
567#else
568 if (effect < Effect::CLICK || effect > Effect::HEAVY_CLICK)
569#endif
Fenglin Wua7baae42020-06-30 15:59:56 +0800570 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
571
572 if (es != EffectStrength::LIGHT && es != EffectStrength::MEDIUM && es != EffectStrength::STRONG)
573 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
574
575 ret = ff.playEffect((static_cast<int>(effect)), es, &playLengthMs);
576 if (ret != 0)
577 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC));
578
579 if (callback != nullptr) {
580 std::thread([=] {
581 ALOGD("Starting perform on another thread");
582 usleep(playLengthMs * 1000);
583 ALOGD("Notifying perform complete");
584 callback->onComplete();
585 }).detach();
586 }
587
588 *_aidl_return = playLengthMs;
589 return ndk::ScopedAStatus::ok();
590}
591
592ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
Kiran Gundab4935072020-07-19 19:30:14 +0530593 if (ledVib.mDetected)
594 return ndk::ScopedAStatus::ok();
595
Kiran Gundaa7032222021-03-24 15:50:49 +0530596#ifdef TARGET_SUPPORTS_OFFLOAD
597 *_aidl_return = {Effect::CLICK, Effect::DOUBLE_CLICK, Effect::TICK, Effect::THUD,
598 Effect::POP, Effect::HEAVY_CLICK, Effect::RINGTONE_12,
599 Effect::RINGTONE_13, Effect::RINGTONE_14, Effect::RINGTONE_15};
600#else
Fenglin Wua7baae42020-06-30 15:59:56 +0800601 *_aidl_return = {Effect::CLICK, Effect::DOUBLE_CLICK, Effect::TICK, Effect::THUD,
602 Effect::POP, Effect::HEAVY_CLICK};
Kiran Gundaa7032222021-03-24 15:50:49 +0530603#endif
Fenglin Wua7baae42020-06-30 15:59:56 +0800604 return ndk::ScopedAStatus::ok();
605}
606
607ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
608 uint8_t tmp;
609 int ret;
610
Kiran Gundab4935072020-07-19 19:30:14 +0530611 if (ledVib.mDetected)
612 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
613
Fenglin Wua7baae42020-06-30 15:59:56 +0800614 ALOGD("Vibrator set amplitude: %f", amplitude);
615
616 if (amplitude <= 0.0f || amplitude > 1.0f)
617 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
618
619 if (ff.mInExternalControl)
620 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
621
622 tmp = (uint8_t)(amplitude * 0xff);
623 ret = ff.setAmplitude(tmp);
624 if (ret != 0)
625 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC));
626
627 return ndk::ScopedAStatus::ok();
628}
629
630ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
Kiran Gundab4935072020-07-19 19:30:14 +0530631 if (ledVib.mDetected)
632 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
633
Fenglin Wua7baae42020-06-30 15:59:56 +0800634 ALOGD("Vibrator set external control: %d", enabled);
635 if (!ff.mSupportExternalControl)
636 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
637
638 ff.mInExternalControl = enabled;
639 return ndk::ScopedAStatus::ok();
640}
641
642ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* maxDelayMs __unused) {
643 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
644}
645
646ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize __unused) {
647 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
648}
649
650ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* supported __unused) {
651 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
652}
653
654ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive __unused,
655 int32_t* durationMs __unused) {
656 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
657}
658
659ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite __unused,
660 const std::shared_ptr<IVibratorCallback>& callback __unused) {
661 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
662}
663
664ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return __unused) {
665 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
666}
667
668ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id __unused, Effect effect __unused,
669 EffectStrength strength __unused) {
670 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
671}
672
673ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id __unused) {
674 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
675}
676
677} // namespace vibrator
678} // namespace hardware
679} // namespace android
680} // namespace aidl
681