1 /*
2  * Copyright (c) 2023 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_drag_context.h"
17 
18 #include "devicestatus_define.h"
19 #include "drag_data.h"
20 #include "napi_constants.h"
21 #include "util_napi_error.h"
22 
23 #undef LOG_TAG
24 #define LOG_TAG "JsDragContext"
25 
26 namespace OHOS {
27 namespace Msdp {
28 namespace DeviceStatus {
29 namespace {
30 const char* DRAG_CLASS { "drag_class" };
31 const char* DRAG { "drag" };
32 inline constexpr size_t MAX_STRING_LEN { 1024 };
33 } // namespace
34 
JsDragContext()35 JsDragContext::JsDragContext()
36     : mgr_(std::make_shared<JsDragManager>()) {}
37 
~JsDragContext()38 JsDragContext::~JsDragContext()
39 {
40     std::lock_guard<std::mutex> guard(mutex_);
41     if (mgr_ != nullptr) {
42         mgr_->ResetEnv();
43         mgr_ = nullptr;
44     }
45 }
46 
GetJsDragMgr()47 std::shared_ptr<JsDragManager> JsDragContext::GetJsDragMgr()
48 {
49     std::lock_guard<std::mutex> guard(mutex_);
50     return mgr_;
51 }
52 
CreateInstance(napi_env env)53 napi_value JsDragContext::CreateInstance(napi_env env)
54 {
55     CALL_INFO_TRACE;
56     napi_value global = nullptr;
57     CHKRP(napi_get_global(env, &global), GET_GLOBAL);
58 
59     constexpr char className[] = "JsDragContext";
60     napi_value jsClass = nullptr;
61     napi_property_descriptor desc[] = {};
62     napi_status status = napi_define_class(env, className, sizeof(className),
63         JsDragContext::JsConstructor, nullptr, sizeof(desc) / sizeof(desc[0]), nullptr, &jsClass);
64     CHKRP(status, DEFINE_CLASS);
65 
66     status = napi_set_named_property(env, global, DRAG_CLASS, jsClass);
67     CHKRP(status, SET_NAMED_PROPERTY);
68 
69     napi_value jsInstance = nullptr;
70     CHKRP(napi_new_instance(env, jsClass, 0, nullptr, &jsInstance), NEW_INSTANCE);
71     CHKRP(napi_set_named_property(env, global, DRAG, jsInstance),
72         SET_NAMED_PROPERTY);
73 
74     JsDragContext *jsContext = nullptr;
75     CHKRP(napi_unwrap(env, jsInstance, reinterpret_cast<void**>(&jsContext)), UNWRAP);
76     CHKPP(jsContext);
77     CHKRP(napi_create_reference(env, jsInstance, 1, &(jsContext->contextRef_)), CREATE_REFERENCE);
78 
79     uint32_t refCount = 0;
80     status = napi_reference_ref(env, jsContext->contextRef_, &refCount);
81     if (status != napi_ok) {
82         FI_HILOGE("ref is nullptr");
83         napi_delete_reference(env, jsContext->contextRef_);
84         return nullptr;
85     }
86     return jsInstance;
87 }
88 
JsConstructor(napi_env env,napi_callback_info info)89 napi_value JsDragContext::JsConstructor(napi_env env, napi_callback_info info)
90 {
91     CALL_INFO_TRACE;
92     napi_value thisVar = nullptr;
93     void *data = nullptr;
94     CHKRP(napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data), GET_CB_INFO);
95 
96     JsDragContext *jsContext = new (std::nothrow) JsDragContext();
97     CHKPP(jsContext);
98     napi_status status = napi_wrap(env, thisVar, jsContext, [](napi_env env, void *data, void *hin) {
99         FI_HILOGI("Jsvm ends");
100         JsDragContext *context = static_cast<JsDragContext*>(data);
101         delete context;
102     }, nullptr, nullptr);
103     if (status != napi_ok) {
104         delete jsContext;
105         FI_HILOGE("%{public}s failed", std::string(WRAP).c_str());
106         auto errInfoTemp = std::string(__FUNCTION__) + ": " + std::string(WRAP) + " failed";
107         napi_throw_error(env, nullptr, errInfoTemp.c_str());
108         return nullptr;
109     }
110     return thisVar;
111 }
112 
GetInstance(napi_env env)113 JsDragContext *JsDragContext::GetInstance(napi_env env)
114 {
115     CALL_INFO_TRACE;
116     napi_value global = nullptr;
117     CHKRP(napi_get_global(env, &global), GET_GLOBAL);
118 
119     bool result = false;
120     CHKRP(napi_has_named_property(env, global, DRAG, &result), HAS_NAMED_PROPERTY);
121     if (!result) {
122         FI_HILOGE("Drag was not found");
123         return nullptr;
124     }
125 
126     napi_handle_scope scope = nullptr;
127     napi_open_handle_scope(env, &scope);
128     if (scope == nullptr) {
129         FI_HILOGE("scope is nullptr");
130         return nullptr;
131     }
132     napi_value object = nullptr;
133     CHKRP_SCOPE(env, napi_get_named_property(env, global, DRAG, &object), GET_NAMED_PROPERTY, scope);
134     if (object == nullptr) {
135         napi_close_handle_scope(env, scope);
136         FI_HILOGE("object is nullptr");
137         return nullptr;
138     }
139 
140     JsDragContext *instance = nullptr;
141     CHKRP_SCOPE(env, napi_unwrap(env, object, reinterpret_cast<void**>(&instance)), UNWRAP, scope);
142     if (instance == nullptr) {
143         napi_close_handle_scope(env, scope);
144         FI_HILOGE("instance is nullptr");
145         return nullptr;
146     }
147     napi_close_handle_scope(env, scope);
148     return instance;
149 }
150 
On(napi_env env,napi_callback_info info)151 napi_value JsDragContext::On(napi_env env, napi_callback_info info)
152 {
153     CALL_INFO_TRACE;
154     size_t argc = 2;
155     napi_value argv[2] = { nullptr };
156     CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
157     if (argc < 2) {
158         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Wrong number of parameters");
159         return nullptr;
160     }
161     JsDragContext *jsDev = JsDragContext::GetInstance(env);
162     CHKPP(jsDev);
163     auto jsDragMgr = jsDev->GetJsDragMgr();
164     CHKPP(jsDragMgr);
165     if (!UtilNapi::TypeOf(env, argv[0], napi_string)) {
166         THROWERR(env, COMMON_PARAMETER_ERROR, "type", "string");
167         return nullptr;
168     }
169     char type[MAX_STRING_LEN] = { 0 };
170     size_t strLength = 0;
171     CHKRP(napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &strLength), CREATE_STRING_UTF8);
172     if ((DRAG_TYPE.compare(type)) != 0) {
173         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Type must be drag");
174         return nullptr;
175     }
176     if (!UtilNapi::TypeOf(env, argv[1], napi_function)) {
177         THROWERR(env, COMMON_PARAMETER_ERROR, "callback", "function");
178         return nullptr;
179     }
180     jsDragMgr->RegisterListener(env, argv[1]);
181     return nullptr;
182 }
183 
Off(napi_env env,napi_callback_info info)184 napi_value JsDragContext::Off(napi_env env, napi_callback_info info)
185 {
186     CALL_INFO_TRACE;
187     size_t argc = 2;
188     napi_value argv[2] = { nullptr };
189     CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
190 
191     JsDragContext *jsDev = JsDragContext::GetInstance(env);
192     CHKPP(jsDev);
193     auto jsDragMgr = jsDev->GetJsDragMgr();
194     CHKPP(jsDragMgr);
195     if ((argc == 0) || (!UtilNapi::TypeOf(env, argv[0], napi_string))) {
196         THROWERR(env, COMMON_PARAMETER_ERROR, "type", "string");
197         return nullptr;
198     }
199     char type[MAX_STRING_LEN] = { 0 };
200     size_t length = 0;
201     CHKRP(napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &length), CREATE_STRING_UTF8);
202     if ((DRAG_TYPE.compare(type)) != 0) {
203         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Type must be drag");
204         return nullptr;
205     }
206     if (argc == 1) {
207         jsDragMgr->UnregisterListener(env);
208         return nullptr;
209     }
210     if (UtilNapi::TypeOf(env, argv[1], napi_undefined) || UtilNapi::TypeOf(env, argv[1], napi_null)) {
211         jsDragMgr->UnregisterListener(env);
212         return nullptr;
213     }
214     if (!UtilNapi::TypeOf(env, argv[1], napi_function)) {
215         THROWERR(env, COMMON_PARAMETER_ERROR, "callback", "function");
216         return nullptr;
217     }
218     jsDragMgr->UnregisterListener(env, argv[1]);
219     return nullptr;
220 }
221 
GetDataSummary(napi_env env,napi_callback_info info)222 napi_value JsDragContext::GetDataSummary(napi_env env, napi_callback_info info)
223 {
224     CALL_INFO_TRACE;
225     JsDragContext *jsDev = JsDragContext::GetInstance(env);
226     CHKPP(jsDev);
227     auto jsDragMgr = jsDev->GetJsDragMgr();
228     CHKPP(jsDragMgr);
229     return jsDragMgr->GetDataSummary(env);
230 }
231 
DeclareDragData(napi_env env,napi_value exports)232 void JsDragContext::DeclareDragData(napi_env env, napi_value exports)
233 {
234     napi_value startMsg = nullptr;
235     CHKRV(napi_create_int32(env, static_cast<int32_t>(DragState::START), &startMsg),
236         CREATE_INT32);
237     napi_value stopMsg = nullptr;
238     CHKRV(napi_create_int32(env, static_cast<int32_t>(DragState::STOP), &stopMsg),
239         CREATE_INT32);
240     napi_value cancelMsg = nullptr;
241     CHKRV(napi_create_int32(env, static_cast<int32_t>(DragState::CANCEL), &cancelMsg),
242         CREATE_INT32);
243 
244     napi_property_descriptor msg[] = {
245         DECLARE_NAPI_STATIC_PROPERTY("MSG_DRAG_STATE_START", startMsg),
246         DECLARE_NAPI_STATIC_PROPERTY("MSG_DRAG_STATE_STOP", stopMsg),
247         DECLARE_NAPI_STATIC_PROPERTY("MSG_DRAG_STATE_CANCEL", cancelMsg)
248     };
249 
250     napi_value eventMsg = nullptr;
251     CHKRV(napi_define_class(env, "DragState", NAPI_AUTO_LENGTH, EnumClassConstructor, nullptr,
252         sizeof(msg) / sizeof(*msg), msg, &eventMsg), DEFINE_CLASS);
253     CHKRV(napi_set_named_property(env, exports, "DragState", eventMsg), SET_NAMED_PROPERTY);
254 }
255 
DeclareDragInterface(napi_env env,napi_value exports)256 void JsDragContext::DeclareDragInterface(napi_env env, napi_value exports)
257 {
258     napi_property_descriptor functions[] = {
259         DECLARE_NAPI_STATIC_FUNCTION("on", On),
260         DECLARE_NAPI_STATIC_FUNCTION("off", Off),
261         DECLARE_NAPI_STATIC_FUNCTION("getDataSummary", GetDataSummary)
262     };
263     CHKRV(napi_define_properties(env, exports,
264         sizeof(functions) / sizeof(*functions), functions), DEFINE_PROPERTIES);
265 }
266 
EnumClassConstructor(napi_env env,napi_callback_info info)267 napi_value JsDragContext::EnumClassConstructor(napi_env env, napi_callback_info info)
268 {
269     size_t argc = 0;
270     napi_value args[1] = { nullptr };
271     napi_value result = nullptr;
272     void *data = nullptr;
273     CHKRP(napi_get_cb_info(env, info, &argc, args, &result, &data), GET_CB_INFO);
274     return result;
275 }
276 
Export(napi_env env,napi_value exports)277 napi_value JsDragContext::Export(napi_env env, napi_value exports)
278 {
279     CALL_INFO_TRACE;
280     auto instance = CreateInstance(env);
281     CHKPP(instance);
282     DeclareDragData(env, exports);
283     DeclareDragInterface(env, exports);
284     return exports;
285 }
286 } // namespace DeviceStatus
287 } // namespace Msdp
288 } // namespace OHOS
289