1 /*
2 * Copyright (c) 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 <hitrace_meter.h>
17
18 #include "js_screen_listener.h"
19 #include "js_runtime_utils.h"
20 #include "window_manager_hilog.h"
21 #include "js_screen.h"
22
23 namespace OHOS {
24 namespace Rosen {
25 using namespace AbilityRuntime;
26 inline uint32_t SCREEN_DISCONNECT_TYPE = 0;
27 inline uint32_t SCREEN_CONNECT_TYPE = 1;
28
JsScreenListener(napi_env env)29 JsScreenListener::JsScreenListener(napi_env env) : env_(env), weakRef_(wptr<JsScreenListener> (this))
30 {
31 TLOGI(WmsLogTag::DMS, "Constructor execution");
32 napi_add_env_cleanup_hook(env_, CleanEnv, this);
33 }
34
~JsScreenListener()35 JsScreenListener::~JsScreenListener()
36 {
37 TLOGI(WmsLogTag::DMS, "Destructor execution");
38 napi_remove_env_cleanup_hook(env_, CleanEnv, this);
39 env_ = nullptr;
40 }
41
CleanEnv(void * obj)42 void JsScreenListener::CleanEnv(void* obj)
43 {
44 JsScreenListener* thisObj = reinterpret_cast<JsScreenListener*>(obj);
45 if (!thisObj) {
46 TLOGE(WmsLogTag::DMS, "obj is nullptr");
47 return;
48 }
49 TLOGI(WmsLogTag::DMS, "env_ is invalid, set to nullptr");
50 thisObj->env_ = nullptr;
51 }
52
AddCallback(const std::string & type,napi_value jsListenerObject)53 void JsScreenListener::AddCallback(const std::string& type, napi_value jsListenerObject)
54 {
55 TLOGI(WmsLogTag::DMS, "called");
56 std::lock_guard<std::mutex> lock(mtx_);
57 std::unique_ptr<NativeReference> callbackRef;
58 napi_ref result = nullptr;
59 napi_create_reference(env_, jsListenerObject, 1, &result);
60 callbackRef.reset(reinterpret_cast<NativeReference*>(result));
61 jsCallBack_[type].emplace_back(std::move(callbackRef));
62 TLOGI(WmsLogTag::DMS, "success jsCallBack_ size: %{public}u!",
63 static_cast<uint32_t>(jsCallBack_[type].size()));
64 }
65
RemoveAllCallback()66 void JsScreenListener::RemoveAllCallback()
67 {
68 std::lock_guard<std::mutex> lock(mtx_);
69 jsCallBack_.clear();
70 }
71
RemoveCallback(napi_env env,const std::string & type,napi_value jsListenerObject)72 void JsScreenListener::RemoveCallback(napi_env env, const std::string& type, napi_value jsListenerObject)
73 {
74 std::lock_guard<std::mutex> lock(mtx_);
75 auto it = jsCallBack_.find(type);
76 if (it == jsCallBack_.end()) {
77 TLOGE(WmsLogTag::DMS, "no callback to remove");
78 return;
79 }
80 auto& listeners = it->second;
81 for (auto iter = listeners.begin(); iter != listeners.end();) {
82 bool isEquals = false;
83 napi_strict_equals(env, jsListenerObject, (*iter)->GetNapiValue(), &isEquals);
84 if (isEquals) {
85 listeners.erase(iter);
86 } else {
87 iter++;
88 }
89 }
90 TLOGI(WmsLogTag::DMS, "success jsCallBack_ size: %{public}u!",
91 static_cast<uint32_t>(listeners.size()));
92 }
93
CallJsMethod(const std::string & methodName,napi_value const * argv,size_t argc)94 void JsScreenListener::CallJsMethod(const std::string& methodName, napi_value const * argv, size_t argc)
95 {
96 if (methodName.empty()) {
97 TLOGE(WmsLogTag::DMS, "empty method name str, call method failed");
98 return;
99 }
100 TLOGD(WmsLogTag::DMS, "CallJsMethod methodName = %{public}s", methodName.c_str());
101 if (env_ == nullptr) {
102 TLOGE(WmsLogTag::DMS, "env_ nullptr");
103 return;
104 }
105 for (auto& callback : jsCallBack_[methodName]) {
106 napi_value method = callback->GetNapiValue();
107 if (method == nullptr) {
108 TLOGE(WmsLogTag::DMS, "Failed to get method callback from object");
109 continue;
110 }
111 napi_call_function(env_, NapiGetUndefined(env_), method, argc, argv, nullptr);
112 }
113 }
114
OnConnect(ScreenId id)115 void JsScreenListener::OnConnect(ScreenId id)
116 {
117 std::lock_guard<std::mutex> lock(mtx_);
118 TLOGI(WmsLogTag::DMS, "called");
119 if (jsCallBack_.empty()) {
120 TLOGE(WmsLogTag::DMS, "not register!");
121 return;
122 }
123 if (jsCallBack_.find(EVENT_CONNECT) == jsCallBack_.end()) {
124 TLOGE(WmsLogTag::DMS, "not this event, return");
125 return;
126 }
127 auto napiTask = [self = weakRef_, id, env = env_] () {
128 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsScreenListener::OnConnect");
129 auto thisListener = self.promote();
130 if (thisListener == nullptr || env == nullptr) {
131 TLOGNE(WmsLogTag::DMS, "[NAPI]this listener or env is nullptr");
132 return;
133 }
134 napi_value argv[] = {CreateJsValue(env, static_cast<uint32_t>(id))};
135 thisListener->CallJsMethod(EVENT_CONNECT, argv, ArraySize(argv));
136 };
137
138 if (env_ != nullptr) {
139 napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate, "OnConnect");
140 if (ret != napi_status::napi_ok) {
141 TLOGE(WmsLogTag::DMS, "Failed to SendEvent.");
142 }
143 } else {
144 TLOGE(WmsLogTag::DMS, "env is nullptr");
145 }
146 }
147
OnDisconnect(ScreenId id)148 void JsScreenListener::OnDisconnect(ScreenId id)
149 {
150 std::lock_guard<std::mutex> lock(mtx_);
151 TLOGI(WmsLogTag::DMS, "called");
152 if (jsCallBack_.empty()) {
153 TLOGE(WmsLogTag::DMS, "not register!");
154 return;
155 }
156 if (jsCallBack_.find(EVENT_DISCONNECT) == jsCallBack_.end()) {
157 TLOGE(WmsLogTag::DMS, "not this event, return");
158 return;
159 }
160 auto napiTask = [self = weakRef_, id, env = env_] () {
161 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsScreenListener::OnDisconnect");
162 auto thisListener = self.promote();
163 if (thisListener == nullptr || env == nullptr) {
164 TLOGNE(WmsLogTag::DMS, "[NAPI]this listener or env is nullptr");
165 return;
166 }
167 napi_value argv[] = {CreateJsValue(env, static_cast<uint32_t>(id))};
168 thisListener->CallJsMethod(EVENT_DISCONNECT, argv, ArraySize(argv));
169 };
170
171 if (env_ != nullptr) {
172 napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate, "OnDisconnect");
173 if (ret != napi_status::napi_ok) {
174 TLOGE(WmsLogTag::DMS, "Failed to SendEvent.");
175 }
176 } else {
177 TLOGE(WmsLogTag::DMS, "env is nullptr");
178 }
179 }
180
OnChange(ScreenId id)181 void JsScreenListener::OnChange(ScreenId id)
182 {
183 std::lock_guard<std::mutex> lock(mtx_);
184 TLOGI(WmsLogTag::DMS, "called");
185 if (jsCallBack_.empty()) {
186 TLOGE(WmsLogTag::DMS, "not register!");
187 return;
188 }
189 if (jsCallBack_.find(EVENT_CHANGE) == jsCallBack_.end()) {
190 TLOGE(WmsLogTag::DMS, "not this event, return");
191 return;
192 }
193 auto napiTask = [self = weakRef_, id, env = env_] () {
194 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsScreenListener::OnChange");
195 auto thisListener = self.promote();
196 if (thisListener == nullptr || env == nullptr) {
197 TLOGNE(WmsLogTag::DMS, "[NAPI]this listener or env is nullptr");
198 return;
199 }
200 napi_value argv[] = {CreateJsValue(env, static_cast<uint32_t>(id))};
201 thisListener->CallJsMethod(EVENT_CHANGE, argv, ArraySize(argv));
202 };
203
204 if (env_ != nullptr) {
205 napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate, "OnChange");
206 if (ret != napi_status::napi_ok) {
207 TLOGE(WmsLogTag::DMS, "Failed to SendEvent.");
208 }
209 } else {
210 TLOGE(WmsLogTag::DMS, "env is nullptr");
211 }
212 }
213
CreateScreenIdArray(napi_env env,const std::vector<ScreenId> & data)214 napi_value JsScreenListener::CreateScreenIdArray(napi_env env, const std::vector<ScreenId>& data)
215 {
216 napi_value arrayValue = nullptr;
217 napi_create_array_with_length(env, data.size(), &arrayValue);
218 if (arrayValue == nullptr) {
219 TLOGE(WmsLogTag::DMS, "Failed to create screenid array");
220 return NapiGetUndefined(env);
221 }
222 uint32_t index = 0;
223 for (const auto& item : data) {
224 napi_set_element(env, arrayValue, index++, CreateJsValue(env, static_cast<uint32_t>(item)));
225 }
226 return arrayValue;
227 }
228 } // namespace Rosen
229 } // namespace OHOS
230