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_manager.h"
17 
18 #include "devicestatus_define.h"
19 #include "interaction_manager.h"
20 #include "napi_constants.h"
21 #include "util_napi.h"
22 
23 #undef LOG_TAG
24 #define LOG_TAG "JsDragManager"
25 
26 namespace OHOS {
27 namespace Msdp {
28 namespace DeviceStatus {
29 
ResetEnv()30 void JsDragManager::ResetEnv()
31 {
32     CALL_INFO_TRACE;
33     std::lock_guard<std::mutex> guard(mutex_);
34     listeners_.clear();
35 }
36 
IsSameHandle(napi_env env,napi_value handle,napi_ref ref)37 bool JsDragManager::IsSameHandle(napi_env env, napi_value handle, napi_ref ref)
38 {
39     CALL_INFO_TRACE;
40     napi_handle_scope scope = nullptr;
41     napi_open_handle_scope(env, &scope);
42     CHKPF(scope);
43     napi_value handlerTemp = nullptr;
44     CHKRF_SCOPE(env, napi_get_reference_value(env, ref, &handlerTemp), GET_REFERENCE_VALUE, scope);
45     bool isEqual = false;
46     CHKRF_SCOPE(env, napi_strict_equals(env, handle, handlerTemp, &isEqual), STRICT_EQUALS, scope);
47     napi_close_handle_scope(env, scope);
48     return isEqual;
49 }
50 
GetDataSummary(napi_env env)51 napi_value JsDragManager::GetDataSummary(napi_env env)
52 {
53     CALL_INFO_TRACE;
54     napi_value arr = nullptr;
55     CHKRP(napi_create_array(env, &arr), CREATE_ARRAY);
56     std::map<std::string, int64_t> summarys;
57     if (INTERACTION_MGR->GetDragSummary(summarys, true) != RET_OK) {
58         FI_HILOGE("Failed to GetDragSummary");
59         return arr;
60     }
61     uint32_t index = 0;
62     for (const auto &summary : summarys) {
63         napi_value dataType = nullptr;
64         CHKRP(napi_create_string_utf8(env, summary.first.c_str(), NAPI_AUTO_LENGTH, &dataType), CREATE_STRING_UTF8);
65         napi_value dataSize = nullptr;
66         CHKRP(napi_create_int64(env, summary.second, &dataSize), CREATE_INT64);
67         napi_value object = nullptr;
68         CHKRP(napi_create_object(env, &object), CREATE_OBJECT);
69         CHKRP(napi_set_named_property(env, object, "dataType", dataType), SET_NAMED_PROPERTY);
70         CHKRP(napi_set_named_property(env, object, "dataSize", dataSize), SET_NAMED_PROPERTY);
71         CHKRP(napi_set_element(env, arr, index, object), SET_ELEMENT);
72         ++index;
73     }
74     return arr;
75 }
76 
RegisterListener(napi_env env,napi_value handle)77 void JsDragManager::RegisterListener(napi_env env, napi_value handle)
78 {
79     CALL_INFO_TRACE;
80     std::lock_guard<std::mutex> guard(mutex_);
81     for (const auto &item : listeners_) {
82         CHKPC(item);
83         if (item->env == env && IsSameHandle(env, handle, item->ref)) {
84             FI_HILOGE("The handle already exists");
85             return;
86         }
87     }
88     napi_ref ref = nullptr;
89     CHKRV(napi_create_reference(env, handle, 1, &ref), CREATE_REFERENCE);
90     sptr<CallbackInfo> monitor = new (std::nothrow) CallbackInfo();
91     CHKPV(monitor);
92     monitor->env = env;
93     monitor->ref = ref;
94     listeners_.push_back(std::move(monitor));
95     if (!hasRegistered_) {
96         hasRegistered_ = true;
97         INTERACTION_MGR->AddDraglistener(shared_from_this(), true);
98     }
99 }
100 
UnregisterListener(napi_env env,napi_value handle)101 void JsDragManager::UnregisterListener(napi_env env, napi_value handle)
102 {
103     CALL_INFO_TRACE;
104     std::lock_guard<std::mutex> guard(mutex_);
105     if (listeners_.empty()) {
106         FI_HILOGE("The listener list is empty");
107         return;
108     }
109     for (auto iter = listeners_.begin(); iter != listeners_.end();) {
110         if (handle == nullptr) {
111             RELEASE_CALLBACKINFO((*iter)->env, (*iter)->ref);
112             iter = listeners_.erase(iter);
113         } else {
114             if ((*iter)->env == env && IsSameHandle(env, handle, (*iter)->ref)) {
115                 FI_HILOGD("Removing monitor successfully");
116                 RELEASE_CALLBACKINFO((*iter)->env, (*iter)->ref);
117                 iter = listeners_.erase(iter);
118                 break;
119             }
120             ++iter;
121         }
122     }
123     if (hasRegistered_ && listeners_.empty()) {
124         hasRegistered_ = false;
125         INTERACTION_MGR->RemoveDraglistener(shared_from_this(), true);
126     }
127 }
128 
OnDragMessage(DragState state)129 void JsDragManager::OnDragMessage(DragState state)
130 {
131     CALL_DEBUG_ENTER;
132     std::lock_guard<std::mutex> guard(mutex_);
133     if (listeners_.empty()) {
134         FI_HILOGE("The listener list is empty");
135         return;
136     }
137     for (auto &item : listeners_) {
138         CHKPC(item);
139         CHKPC(item->env);
140         uv_loop_s* loop = nullptr;
141         CHKRV(napi_get_uv_event_loop(item->env, &loop), GET_UV_EVENT_LOOP);
142         uv_work_t* work = new (std::nothrow) uv_work_t;
143         CHKPV(work);
144         item->state = state;
145         item->IncStrongRef(nullptr);
146         work->data = item.GetRefPtr();
147         int32_t result = uv_queue_work_with_qos(loop, work, [](uv_work_t* work) {}, CallDragMsg, uv_qos_default);
148         if (result != 0) {
149             FI_HILOGE("uv_queue_work_with_qos failed");
150             item->DecStrongRef(nullptr);
151             DeletePtr<uv_work_t*>(work);
152         }
153     }
154 }
155 
CallDragMsg(uv_work_t * work,int32_t status)156 void JsDragManager::CallDragMsg(uv_work_t *work, int32_t status)
157 {
158     CALL_DEBUG_ENTER;
159     CHKPV(work);
160     if (work->data == nullptr) {
161         DeletePtr<uv_work_t*>(work);
162         FI_HILOGE("Check data is nullptr");
163         return;
164     }
165     sptr<CallbackInfo> temp(static_cast<CallbackInfo*>(work->data));
166     DeletePtr<uv_work_t*>(work);
167     temp->DecStrongRef(nullptr);
168     std::lock_guard<std::mutex> guard(mutex_);
169     if (listeners_.empty()) {
170         FI_HILOGE("The listener list is empty");
171         return;
172     }
173     for (const auto &item : listeners_) {
174         CHKPC(item->env);
175         if (item->ref != temp->ref) {
176             continue;
177         }
178         napi_handle_scope scope = nullptr;
179         napi_open_handle_scope(item->env, &scope);
180         CHKPC(scope);
181         napi_value stateMsg = nullptr;
182         CHKRV_SCOPE(item->env, napi_create_int32(item->env, static_cast<int32_t>(item->state), &stateMsg),
183             CREATE_INT32, scope);
184         napi_value handler = nullptr;
185         CHKRV_SCOPE(item->env, napi_get_reference_value(item->env, item->ref, &handler), GET_REFERENCE_VALUE, scope);
186         napi_value ret = nullptr;
187         CHKRV_SCOPE(item->env,
188             napi_call_function(item->env, nullptr, handler, 1, &stateMsg, &ret), CALL_FUNCTION, scope);
189         napi_close_handle_scope(item->env, scope);
190     }
191 }
192 } // namespace DeviceStatus
193 } // namespace Msdp
194 } // namespace OHOS
195