1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cstdio>
17 #include <map>
18 #include <string>
19 #include <unistd.h>
20
21 #include "hilog/log.h"
22 #include "napi/native_api.h"
23 #include "napi/native_node_api.h"
24
25 #include "miscdevice_log.h"
26 #include "vibrator_agent.h"
27 #include "vibrator_napi_error.h"
28 #include "vibrator_napi_utils.h"
29
30 namespace OHOS {
31 namespace Sensors {
32 namespace {
33 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, MISC_LOG_DOMAIN, "VibratorJs" };
34 constexpr int32_t VIBRATE_SHORT_DURATION = 35;
35 constexpr int32_t VIBRATE_LONG_DURATION = 1000;
36 } // namespace
37
38 static std::map<std::string, int32_t> g_usageType = {
39 {"unknown", USAGE_UNKNOWN},
40 {"alarm", USAGE_ALARM},
41 {"ring", USAGE_RING},
42 {"notification", USAGE_NOTIFICATION},
43 {"communication", USAGE_COMMUNICATION},
44 {"touch", USAGE_TOUCH},
45 {"media", USAGE_MEDIA},
46 {"physicalFeedback", USAGE_PHYSICAL_FEEDBACK},
47 {"simulateReality", USAGE_SIMULATE_REALITY},
48 };
49
50 struct VibrateInfo {
51 std::string type;
52 std::string usage;
53 int32_t duration = 0;
54 std::string effectId;
55 int32_t count = 0;
56 };
57
VibrateTime(napi_env env,napi_value args[],size_t argc)58 static napi_value VibrateTime(napi_env env, napi_value args[], size_t argc)
59 {
60 NAPI_ASSERT(env, (argc == 1 || argc == 2), "Wrong argument number");
61 int32_t duration = 0;
62 NAPI_ASSERT(env, GetInt32Value(env, args[0], duration), "Get int number fail");
63 sptr<AsyncCallbackInfo> asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo(env);
64 CHKPP(asyncCallbackInfo);
65
66 asyncCallbackInfo->error.code = StartVibratorOnce(duration);
67 if (argc == 2) {
68 NAPI_ASSERT(env, IsMatchType(env, args[1], napi_function), "Wrong argument type. function expected");
69 NAPI_CALL(env, napi_create_reference(env, args[1], 1, &asyncCallbackInfo->callback[0]));
70 EmitAsyncCallbackWork(asyncCallbackInfo);
71 return nullptr;
72 }
73
74 napi_deferred deferred = nullptr;
75 napi_value promise = nullptr;
76 NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
77 asyncCallbackInfo->deferred = deferred;
78 EmitPromiseWork(asyncCallbackInfo);
79 return promise;
80 }
81
VibrateEffectId(napi_env env,napi_value args[],size_t argc)82 static napi_value VibrateEffectId(napi_env env, napi_value args[], size_t argc)
83 {
84 NAPI_ASSERT(env, (argc == 1 || argc == 2), "Wrong argument number");
85 string effectId;
86 NAPI_ASSERT(env, GetStringValue(env, args[0], effectId), "Wrong argument type. String or function expected");
87 sptr<AsyncCallbackInfo> asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo(env);
88 CHKPP(asyncCallbackInfo);
89 asyncCallbackInfo->error.code = StartVibrator(effectId.c_str());
90
91 if (argc == 2) {
92 NAPI_ASSERT(env, IsMatchType(env, args[1], napi_function), "Wrong argument type. function expected");
93 NAPI_CALL(env, napi_create_reference(env, args[1], 1, &asyncCallbackInfo->callback[0]));
94 EmitAsyncCallbackWork(asyncCallbackInfo);
95 return nullptr;
96 }
97
98 napi_deferred deferred = nullptr;
99 napi_value promise = nullptr;
100 NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
101 asyncCallbackInfo->deferred = deferred;
102 EmitPromiseWork(asyncCallbackInfo);
103 return promise;
104 }
105
GetCallbackInfo(const napi_env & env,napi_value args[],sptr<AsyncCallbackInfo> & asyncCallbackInfo,string & mode)106 static bool GetCallbackInfo(const napi_env &env, napi_value args[],
107 sptr<AsyncCallbackInfo> &asyncCallbackInfo, string &mode)
108 {
109 CHKPF(asyncCallbackInfo);
110 CHKPF(args);
111 napi_value value = nullptr;
112 NAPI_CALL_BASE(env, napi_get_named_property(env, args[0], "success", &value), false);
113 NAPI_CALL_BASE(env, napi_create_reference(env, value, 1, &asyncCallbackInfo->callback[0]), false);
114
115 bool result = false;
116 NAPI_CALL_BASE(env, napi_has_named_property(env, args[0], "mode", &result), false);
117 if (result) {
118 NAPI_CALL_BASE(env, napi_get_named_property(env, args[0], "mode", &value), false);
119 NAPI_ASSERT_BASE(env, GetStringValue(env, value, mode),
120 "Wrong argument type. String or function expected", false);
121 NAPI_ASSERT_BASE(env, (mode == "long" || mode == "short"),
122 "Wrong argument type. Invalid mode value", false);
123 }
124 NAPI_CALL_BASE(env, napi_has_named_property(env, args[0], "fail", &result), false);
125 if (result) {
126 NAPI_CALL_BASE(env, napi_get_named_property(env, args[0], "fail", &value), false);
127 NAPI_CALL_BASE(env, napi_create_reference(env, value, 1, &asyncCallbackInfo->callback[1]), false);
128 }
129 NAPI_CALL_BASE(env, napi_has_named_property(env, args[0], "complete", &result), false);
130 if (result) {
131 NAPI_CALL_BASE(env, napi_get_named_property(env, args[0], "complete", &value), false);
132 NAPI_CALL_BASE(env, napi_create_reference(env, value, 1, &asyncCallbackInfo->callback[2]), false);
133 }
134 return true;
135 }
136
VibrateMode(napi_env env,napi_value args[],size_t argc)137 static napi_value VibrateMode(napi_env env, napi_value args[], size_t argc)
138 {
139 if (argc == 0) {
140 NAPI_ASSERT(env, (StartVibratorOnce(VIBRATE_LONG_DURATION) == 0), "Vibrate long mode fail");
141 return nullptr;
142 }
143 NAPI_ASSERT(env, (argc == 1), "Param number is invalid");
144 sptr<AsyncCallbackInfo> asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo(env);
145 CHKPP(asyncCallbackInfo);
146 asyncCallbackInfo->callbackType = TYPE_SYSTEM_VIBRATE;
147 string mode = "long";
148 NAPI_ASSERT(env, GetCallbackInfo(env, args, asyncCallbackInfo, mode), "Get callback info fail");
149 int32_t duration = ((mode == "long") ? VIBRATE_LONG_DURATION : VIBRATE_SHORT_DURATION);
150 asyncCallbackInfo->error.code = StartVibratorOnce(duration);
151 if (asyncCallbackInfo->error.code != SUCCESS) {
152 asyncCallbackInfo->error.message = "Vibrator vibrate fail";
153 }
154 EmitAsyncCallbackWork(asyncCallbackInfo);
155 return nullptr;
156 }
157
ParseParameter(napi_env env,napi_value args[],size_t argc,VibrateInfo & info)158 bool ParseParameter(napi_env env, napi_value args[], size_t argc, VibrateInfo &info)
159 {
160 CHKCF((argc >= 2), "Wrong argument number");
161 CHKCF(GetPropertyString(env, args[0], "type", info.type), "Get vibrate type fail");
162 if (info.type == "time") {
163 CHKCF(GetPropertyInt32(env, args[0], "duration", info.duration), "Get vibrate type fail");
164 } else if (info.type == "preset") {
165 CHKCF(GetPropertyInt32(env, args[0], "count", info.count), "Get vibrate count fail");
166 CHKCF(GetPropertyString(env, args[0], "effectId", info.effectId), "Get vibrate effectId fail");
167 }
168 CHKCF(GetPropertyString(env, args[1], "usage", info.usage), "Get vibrate usage fail");
169 return true;
170 }
171
SetUsage(const std::string & usage)172 bool SetUsage(const std::string &usage)
173 {
174 if (auto iter = g_usageType.find(usage); iter == g_usageType.end()) {
175 MISC_HILOGE("Wrong usage type");
176 return false;
177 }
178 return SetUsage(g_usageType[usage]);
179 }
180
StartVibrate(const VibrateInfo & info)181 int32_t StartVibrate(const VibrateInfo &info)
182 {
183 if (!SetUsage(info.usage)) {
184 MISC_HILOGE("SetUsage fail");
185 return PARAMETER_ERROR;
186 }
187 if ((info.type != "time") && (info.type != "preset")) {
188 MISC_HILOGE("Invalid vibrate type");
189 return PARAMETER_ERROR;
190 }
191 if (info.type == "preset") {
192 if (!SetLoopCount(info.count)) {
193 MISC_HILOGE("SetLoopCount fail");
194 return PARAMETER_ERROR;
195 }
196 return StartVibrator(info.effectId.c_str());
197 }
198 return StartVibratorOnce(info.duration);
199 }
200
VibrateEffect(napi_env env,napi_value args[],size_t argc)201 static napi_value VibrateEffect(napi_env env, napi_value args[], size_t argc)
202 {
203 VibrateInfo info;
204 if (!ParseParameter(env, args, argc, info)) {
205 ThrowErr(env, PARAMETER_ERROR, "parameter fail");
206 return nullptr;
207 }
208 sptr<AsyncCallbackInfo> asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo(env);
209 CHKPP(asyncCallbackInfo);
210 asyncCallbackInfo->error.code = StartVibrate(info);
211 if ((asyncCallbackInfo->error.code != SUCCESS) && (asyncCallbackInfo->error.code == PARAMETER_ERROR)) {
212 ThrowErr(env, PARAMETER_ERROR, "parameters invalid");
213 return nullptr;
214 }
215 if (argc >= 3) {
216 if (!IsMatchType(env, args[2], napi_function)) {
217 ThrowErr(env, PARAMETER_ERROR, "IsMatchType fail, should be function");
218 return nullptr;
219 }
220 if (napi_create_reference(env, args[2], 1, &asyncCallbackInfo->callback[0]) != napi_ok) {
221 ThrowErr(env, PARAMETER_ERROR, "napi_create_reference fail");
222 return nullptr;
223 }
224 EmitAsyncCallbackWork(asyncCallbackInfo);
225 return nullptr;
226 }
227 napi_deferred deferred = nullptr;
228 napi_value promise = nullptr;
229 CHKCP((napi_create_promise(env, &deferred, &promise) == napi_ok), "napi_create_promise fail");
230 asyncCallbackInfo->deferred = deferred;
231 EmitPromiseWork(asyncCallbackInfo);
232 return promise;
233 }
234
Vibrate(napi_env env,napi_callback_info info)235 static napi_value Vibrate(napi_env env, napi_callback_info info)
236 {
237 CHKPP(env);
238 CHKPP(info);
239 size_t argc = 3;
240 napi_value args[3] = {};
241 napi_value thisArg = nullptr;
242 napi_status status = napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr);
243 if ((status != napi_ok) || (argc == 0)) {
244 ThrowErr(env, PARAMETER_ERROR, "napi_get_cb_info fail or number of parameter invalid");
245 return nullptr;
246 }
247 if (IsMatchType(env, args[0], napi_number)) {
248 return VibrateTime(env, args, argc);
249 }
250 if (IsMatchType(env, args[0], napi_string)) {
251 return VibrateEffectId(env, args, argc);
252 }
253 if (IsMatchType(env, args[0], napi_object) && argc == 1) {
254 return VibrateMode(env, args, argc);
255 }
256 return VibrateEffect(env, args, argc);
257 }
258
Stop(napi_env env,napi_callback_info info)259 static napi_value Stop(napi_env env, napi_callback_info info)
260 {
261 size_t argc = 2;
262 napi_value args[2] = {};
263 napi_value thisArg = nullptr;
264 napi_status status = napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr);
265 if ((status != napi_ok) || (argc == 0)) {
266 ThrowErr(env, PARAMETER_ERROR, "napi_get_cb_info fail or number of parameter invalid");
267 return nullptr;
268 }
269 string mode;
270 if (!GetStringValue(env, args[0], mode)) {
271 ThrowErr(env, PARAMETER_ERROR, "GetStringValue fail");
272 return nullptr;
273 }
274 sptr<AsyncCallbackInfo> asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo(env);
275 CHKPP(asyncCallbackInfo);
276 asyncCallbackInfo->error.code = StopVibrator(mode.c_str());
277 if ((asyncCallbackInfo->error.code != SUCCESS) && (asyncCallbackInfo->error.code == PARAMETER_ERROR)) {
278 ThrowErr(env, PARAMETER_ERROR, "Parameters invalid");
279 return nullptr;
280 }
281 if (argc >= 2) {
282 if (!IsMatchType(env, args[1], napi_function)) {
283 ThrowErr(env, PARAMETER_ERROR, "IsMatchType fail, should be function");
284 return nullptr;
285 }
286 if (napi_create_reference(env, args[1], 1, &asyncCallbackInfo->callback[0]) != napi_ok) {
287 ThrowErr(env, PARAMETER_ERROR, "napi_create_reference fail");
288 return nullptr;
289 }
290 EmitAsyncCallbackWork(asyncCallbackInfo);
291 return nullptr;
292 }
293 napi_deferred deferred = nullptr;
294 napi_value promise = nullptr;
295 CHKCP((napi_create_promise(env, &deferred, &promise) == napi_ok), "napi_create_promise fail");
296 asyncCallbackInfo->deferred = deferred;
297 EmitPromiseWork(asyncCallbackInfo);
298 return promise;
299 }
300
EnumClassConstructor(const napi_env env,const napi_callback_info info)301 static napi_value EnumClassConstructor(const napi_env env, const napi_callback_info info)
302 {
303 size_t argc = 0;
304 napi_value args[1] = {0};
305 napi_value res = nullptr;
306 void *data = nullptr;
307 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &res, &data));
308 return res;
309 }
310
CreateEnumStopMode(const napi_env env,napi_value exports)311 static napi_value CreateEnumStopMode(const napi_env env, napi_value exports)
312 {
313 napi_value timeMode = nullptr;
314 napi_value presetMode = nullptr;
315 NAPI_CALL(env, napi_create_string_utf8(env, "time", NAPI_AUTO_LENGTH, &timeMode));
316 NAPI_CALL(env, napi_create_string_utf8(env, "preset", NAPI_AUTO_LENGTH, &presetMode));
317
318 napi_property_descriptor desc[] = {
319 DECLARE_NAPI_STATIC_PROPERTY("VIBRATOR_STOP_MODE_TIME", timeMode),
320 DECLARE_NAPI_STATIC_PROPERTY("VIBRATOR_STOP_MODE_PRESET", presetMode),
321 };
322 napi_value result = nullptr;
323 NAPI_CALL(env, napi_define_class(env, "VibratorStopMode", NAPI_AUTO_LENGTH, EnumClassConstructor, nullptr,
324 sizeof(desc) / sizeof(*desc), desc, &result));
325 NAPI_CALL(env, napi_set_named_property(env, exports, "VibratorStopMode", result));
326 return exports;
327 }
328
CreateEnumEffectId(const napi_env env,const napi_value exports)329 static napi_value CreateEnumEffectId(const napi_env env, const napi_value exports)
330 {
331 napi_value clockTime = nullptr;
332 napi_create_string_utf8(env, "haptic.clock.timer", NAPI_AUTO_LENGTH, &clockTime);
333 napi_property_descriptor desc[] = {
334 DECLARE_NAPI_STATIC_PROPERTY("EFFECT_CLOCK_TIMER", clockTime),
335 };
336 napi_value result = nullptr;
337 NAPI_CALL(env, napi_define_class(env, "EffectId", NAPI_AUTO_LENGTH, EnumClassConstructor, nullptr,
338 sizeof(desc) / sizeof(*desc), desc, &result));
339 NAPI_CALL(env, napi_set_named_property(env, exports, "EffectId", result));
340 return exports;
341 }
342
Init(napi_env env,napi_value exports)343 static napi_value Init(napi_env env, napi_value exports)
344 {
345 napi_property_descriptor desc[] = {
346 DECLARE_NAPI_FUNCTION("vibrate", Vibrate),
347 DECLARE_NAPI_FUNCTION("stop", Stop),
348 DECLARE_NAPI_FUNCTION("startVibration", Vibrate),
349 DECLARE_NAPI_FUNCTION("stopVibration", Stop),
350 };
351 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc));
352 NAPI_ASSERT_BASE(env, CreateEnumStopMode(env, exports) != nullptr, "Create enum stop mode fail", exports);
353 NAPI_ASSERT_BASE(env, CreateEnumEffectId(env, exports) != nullptr, "Create enum effect id fail", exports);
354 return exports;
355 }
356
357 static napi_module _module = {
358 .nm_version = 1,
359 .nm_flags = 0,
360 .nm_filename = nullptr,
361 .nm_register_func = Init,
362 .nm_modname = "vibrator",
363 .nm_priv = ((void *)0),
364 .reserved = {0}
365 };
366
RegisterModule(void)367 extern "C" __attribute__((constructor)) void RegisterModule(void)
368 {
369 napi_module_register(&_module);
370 }
371 } // namespace Sensors
372 } // namespace OHOS
373