1 /*
2  * Copyright (c) 2024 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 "js_register_module.h"
17 #include <linux/input.h>
18 
19 #include "input_manager.h"
20 #include "mmi_log.h"
21 #include "napi_constants.h"
22 #include "util_napi_error.h"
23 #include "util_napi.h"
24 
25 #undef MMI_LOG_TAG
26 #define MMI_LOG_TAG "JsInfraredRegister"
27 
28 namespace OHOS {
29 namespace MMI {
30 namespace {
31 const uint32_t NUMBER_PARAMETERS { 2 };
32 constexpr int32_t MAX_NUMBER_ARRAY_ELEMENT { 1024 };
33 }
34 
CheckType(const napi_env & env,const napi_value & value,const napi_valuetype & type)35 bool CheckType(const napi_env& env, const napi_value& value, const napi_valuetype& type)
36 {
37     napi_valuetype valuetype = napi_undefined;
38     napi_typeof(env, value, &valuetype);
39     if (valuetype != type) {
40         return false;
41     }
42     return true;
43 }
44 
IsArray(const napi_env & env,const napi_value & value)45 bool IsArray(const napi_env& env, const napi_value& value)
46 {
47     bool isArray = false;
48     if (napi_is_array(env, value, &isArray) != napi_ok) {
49         MMI_HILOGE("napi_is_array failed");
50         return false;
51     }
52     return isArray;
53 }
54 
ParseInt64(const napi_env & env,const napi_value & value,int64_t & result)55 bool ParseInt64(const napi_env& env, const napi_value& value, int64_t& result)
56 {
57     if (!CheckType(env, value, napi_number)) {
58         MMI_HILOGE("ParseInt64 type not number");
59         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "element of pattern", "Number");
60         return false;
61     }
62     if (napi_get_value_int64(env, value, &result) != napi_ok) {
63         MMI_HILOGE("ParseInt64 cannot get value int64");
64         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "element of pattern", "Int64");
65         return false;
66     }
67     return true;
68 }
69 
ParsePatternArray(const napi_env & env,const napi_value & value,std::vector<int64_t> & result)70 bool ParsePatternArray(const napi_env& env, const napi_value& value, std::vector<int64_t>& result)
71 {
72     uint32_t length = 0;
73     if (!IsArray(env, value)) {
74         MMI_HILOGE("ParsePatternArray second para not array");
75         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "pattern", "Array");
76         return false;
77     }
78     napi_get_array_length(env, value, &length);
79     for (uint32_t i = 0; i < length; i++) {
80         napi_value valueArray = nullptr;
81         if (napi_get_element(env, value, i, &valueArray) != napi_ok) {
82             MMI_HILOGE("ParsePatternArray napi_get_element failed. index:%{public}d", i);
83             return false;
84         }
85         int64_t res = 0;
86         if (!ParseInt64(env, valueArray, res)) {
87             MMI_HILOGE("ParsePatternArray parse array fail. index:%{public}d", i);
88             THROWERR_API9(env, COMMON_PARAMETER_ERROR, "element of pattern", "Int64");
89             return false;
90         }
91         if (res <= 0) {
92             THROWERR_API9(env, COMMON_PARAMETER_ERROR, "value for element of pattern", "must be positive");
93             return false;
94         }
95         result.emplace_back(res);
96     }
97     return true;
98 };
99 
ParseTransmitInfraredJSParam(const napi_env & env,const napi_callback_info & info,int64_t & infraredFrequency,std::vector<int64_t> & vecPattern)100 bool ParseTransmitInfraredJSParam(const napi_env& env, const napi_callback_info &info, int64_t & infraredFrequency,
101                                   std::vector<int64_t> & vecPattern)
102 {
103     CALL_DEBUG_ENTER;
104     size_t argc = NUMBER_PARAMETERS;
105     napi_value argv[NUMBER_PARAMETERS] = { 0 };
106     CHKRF(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
107     if (argc != NUMBER_PARAMETERS) {
108         MMI_HILOGE("ParseTransmitInfraredJSParam Parameter number error");
109         return false;
110     }
111     if (!CheckType(env, argv[0], napi_number)) {
112         MMI_HILOGE("ParseTransmitInfraredJSParam infraredFrequency parameter[0] type is invalid");
113         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "infraredFrequency", "number");
114         return false;
115     }
116     CHKRF(napi_get_value_int64(env, argv[0], &infraredFrequency), "get number64 value error");
117     if (infraredFrequency <= 0) {
118         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "value of infraredFrequency", "must be greater than 0");
119         return false;
120     }
121     if (!ParsePatternArray(env, argv[1], vecPattern)) {
122         MMI_HILOGE("ParsePatternArray parse pattern array fail");
123         return false;
124     }
125     if (vecPattern.size() > MAX_NUMBER_ARRAY_ELEMENT) {
126         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "size of pattern", "must be less than or equal 50");
127         return false;
128     }
129     return true;
130 }
131 
ThrowError(napi_env env,int32_t code,std::string operateType)132 static void ThrowError(napi_env env, int32_t code, std::string operateType)
133 {
134     int32_t errorCode = -code;
135     if (code > 0) {
136         errorCode = code;
137     }
138     MMI_HILOGE("Operate %{public}s requst error. returnCode:%{public}d", operateType.c_str(), code);
139     if (errorCode == COMMON_PERMISSION_CHECK_ERROR) {
140         THROWERR_API9(env, COMMON_PERMISSION_CHECK_ERROR, "Infrared", "ohos.permission.MANAGE_INPUT_INFRARED_EMITTER");
141     } else if (COMMON_USE_SYSAPI_ERROR == errorCode) {
142         THROWERR_API9(env, COMMON_USE_SYSAPI_ERROR, "Infrared", "Non system applications use system API");
143     } else {
144         return;
145     }
146 }
147 
CreateInfraredFrequencyItem(napi_env env,const InfraredFrequency & infraredFrequency)148 napi_value CreateInfraredFrequencyItem(napi_env env, const InfraredFrequency &infraredFrequency)
149 {
150     napi_value result;
151     napi_status status = napi_create_object(env, &result);
152     CHKRP(status, CREATE_OBJECT);
153     napi_value jsMax;
154     CHKRP(napi_create_int64(env, infraredFrequency.max_, &jsMax), "napi_create_int64:max");
155     CHKRP(napi_set_named_property(env, result, "max", jsMax), SET_NAMED_PROPERTY);
156     napi_value jsMin;
157     CHKRP(napi_create_int64(env, infraredFrequency.min_, &jsMin), "napi_create_int64:min");
158     CHKRP(napi_set_named_property(env, result, "min", jsMin), SET_NAMED_PROPERTY);
159     return result;
160 }
161 
HasIrEmitter(napi_env env,napi_callback_info info)162 static napi_value HasIrEmitter(napi_env env, napi_callback_info info)
163 {
164     CALL_DEBUG_ENTER;
165     napi_value result = nullptr;
166     napi_status status = napi_get_boolean(env, true, &result);
167     if (status != napi_ok) {
168         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "type", "boolean");
169         return nullptr;
170     }
171     return result;
172 }
173 
GetInfraredFrequencies(napi_env env,napi_callback_info info)174 static napi_value GetInfraredFrequencies(napi_env env, napi_callback_info info)
175 {
176     CALL_DEBUG_ENTER;
177     napi_value result = nullptr;
178     CHKRP(napi_create_array(env, &result), CREATE_ARRAY);
179     std::vector<InfraredFrequency> requencys;
180     int32_t ret = InputManager::GetInstance()->GetInfraredFrequencies(requencys);
181     if (ret != RET_OK) {
182         if (RET_OK > ret || COMMON_PERMISSION_CHECK_ERROR == ret || ERROR_NOT_SYSAPI == ret) {
183             MMI_HILOGE("js_register.GetFreq reqErr. Permi Err or Not System APP. Positive retCode:%{public}d", ret);
184             ThrowError(env, ret, "GetInfraredFrequencies");
185         }
186         MMI_HILOGE("Parse GetInfraredFrequencies requst error. returnCode:%{public}d", ret);
187         return result;
188     }
189     size_t size = requencys.size();
190     std::string logPrint = "size:" + std::to_string(size) + ";";
191     CHKRP(napi_create_array(env, &result), CREATE_ARRAY);
192     for (size_t i = 0; i < size; i++) {
193         InfraredFrequency frequencyItem = requencys[i];
194         logPrint = logPrint + std::to_string(i) + "max:" + std::to_string(frequencyItem.max_) + ";min:"
195                     + std::to_string(frequencyItem.min_) + ";";
196         napi_value item = CreateInfraredFrequencyItem(env, requencys[i]);
197         if (item == nullptr) {
198             MMI_HILOGE("CreateInfraredFrequencyItem error");
199             return nullptr;
200         }
201         CHKRP(napi_set_element(env, result, i, item), SET_ELEMENT);
202     }
203     MMI_HILOGD("js_register_module.GetInfraredFrequencies:%{public}s ", logPrint.c_str());
204     return result;
205 }
206 
TransmitInfrared(napi_env env,napi_callback_info info)207 static napi_value TransmitInfrared(napi_env env, napi_callback_info info)
208 {
209     CALL_DEBUG_ENTER;
210     napi_value result = nullptr;
211     int64_t number = -1;
212     std::vector<int64_t> pattern;
213     if (!ParseTransmitInfraredJSParam(env, info, number, pattern)) {
214         MMI_HILOGE("Parse TransmitInfrared JSParam error");
215         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Parse TransmitInfrared JSParam error");
216         return nullptr;
217     }
218     int32_t size = static_cast<int32_t>(pattern.size());
219     std::string context = "number:" + std::to_string(number) + "\n;" + "; size=" + std::to_string(size) + ";";
220     for (int32_t i = 0; i < size; i++) {
221         context = context + std::to_string(i) + ": pattern: " + std::to_string(pattern[i]) + ";";
222     }
223     MMI_HILOGD("js_register_module.TransmitInfrared para size:%{public}s", context.c_str());
224     int32_t ret = InputManager::GetInstance()->TransmitInfrared(number, pattern);
225     if (ret != RET_OK) {
226         if (RET_OK > ret || COMMON_PERMISSION_CHECK_ERROR == ret || ERROR_NOT_SYSAPI == ret) {
227             MMI_HILOGE("js_register.Transmit req err. Per Er or Not Sys APP. Posi retCode:%{public}d", ret);
228             ThrowError(env, ret, "TransmitInfrared");
229         }
230         MMI_HILOGE("js_register_module.TransmitInfrared requst error. returnCode:%{public}d", ret);
231         return nullptr;
232     }
233     CHKRP(napi_create_int32(env, 0, &result), CREATE_INT32);
234     return result;
235 }
236 
237 EXTERN_C_START
MmiInit(napi_env env,napi_value exports)238 static napi_value MmiInit(napi_env env, napi_value exports)
239 {
240     CALL_DEBUG_ENTER;
241     napi_property_descriptor desc[] = {
242         DECLARE_NAPI_FUNCTION("hasIrEmitter", HasIrEmitter),
243         DECLARE_NAPI_FUNCTION("getInfraredFrequencies", GetInfraredFrequencies),
244         DECLARE_NAPI_FUNCTION("transmitInfrared", TransmitInfrared)
245     };
246     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
247     return exports;
248 }
249 EXTERN_C_END
250 
251 static napi_module infraredModule = {
252     .nm_version = 1,
253     .nm_flags = 0,
254     .nm_filename = nullptr,
255     .nm_register_func = MmiInit,
256     .nm_modname = "multimodalInput.infraredEmitter",
257     .nm_priv = ((void*)0),
258     .reserved = { 0 },
259 };
260 
RegisterModule(void)261 extern "C" __attribute__((constructor)) void RegisterModule(void)
262 {
263     napi_module_register(&infraredModule);
264 }
265 
266 }
267 }