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 "js_display_listener.h"
17
18 #include <hitrace_meter.h>
19
20 #include "dm_common.h"
21 #include "js_runtime_utils.h"
22 #include "window_manager_hilog.h"
23 #include "js_display.h"
24
25 namespace OHOS {
26 namespace Rosen {
27 using namespace AbilityRuntime;
28
JsDisplayListener(napi_env env)29 JsDisplayListener::JsDisplayListener(napi_env env) : env_(env), weakRef_(wptr<JsDisplayListener> (this))
30 {
31 TLOGI(WmsLogTag::DMS, "Constructor execution");
32 napi_add_env_cleanup_hook(env_, CleanEnv, this);
33 }
34
~JsDisplayListener()35 JsDisplayListener::~JsDisplayListener()
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 JsDisplayListener::CleanEnv(void* obj)
43 {
44 JsDisplayListener* thisObj = reinterpret_cast<JsDisplayListener*>(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 JsDisplayListener::AddCallback(const std::string& type, napi_value jsListenerObject)
54 {
55 TLOGD(WmsLogTag::DMS, "called");
56 std::unique_ptr<NativeReference> callbackRef;
57 if (env_ == nullptr) {
58 TLOGE(WmsLogTag::DMS, "env_ nullptr");
59 return;
60 }
61 napi_ref result = nullptr;
62 napi_create_reference(env_, jsListenerObject, 1, &result);
63 callbackRef.reset(reinterpret_cast<NativeReference*>(result));
64 std::lock_guard<std::mutex> lock(mtx_);
65 jsCallBack_[type].emplace_back(std::move(callbackRef));
66 TLOGD(WmsLogTag::DMS, "success jsCallBack_ size: %{public}u!",
67 static_cast<uint32_t>(jsCallBack_[type].size()));
68 }
69
RemoveAllCallback()70 void JsDisplayListener::RemoveAllCallback()
71 {
72 std::lock_guard<std::mutex> lock(mtx_);
73 jsCallBack_.clear();
74 }
75
RemoveCallback(napi_env env,const std::string & type,napi_value jsListenerObject)76 void JsDisplayListener::RemoveCallback(napi_env env, const std::string& type, napi_value jsListenerObject)
77 {
78 std::lock_guard<std::mutex> lock(mtx_);
79 auto it = jsCallBack_.find(type);
80 if (it == jsCallBack_.end()) {
81 TLOGE(WmsLogTag::DMS, "no callback to remove");
82 return;
83 }
84 auto& listeners = it->second;
85 for (auto iter = listeners.begin(); iter != listeners.end();) {
86 bool isEquals = false;
87 napi_strict_equals(env, jsListenerObject, (*iter)->GetNapiValue(), &isEquals);
88 if (isEquals) {
89 listeners.erase(iter);
90 } else {
91 iter++;
92 }
93 }
94 TLOGI(WmsLogTag::DMS, "success jsCallBack_ size: %{public}u!",
95 static_cast<uint32_t>(listeners.size()));
96 }
97
CallJsMethod(const std::string & methodName,napi_value const * argv,size_t argc)98 void JsDisplayListener::CallJsMethod(const std::string& methodName, napi_value const * argv, size_t argc)
99 {
100 if (methodName.empty()) {
101 TLOGE(WmsLogTag::DMS, "empty method name str, call method failed");
102 return;
103 }
104 TLOGD(WmsLogTag::DMS, "CallJsMethod methodName = %{public}s", methodName.c_str());
105 if (env_ == nullptr) {
106 TLOGE(WmsLogTag::DMS, "env_ nullptr");
107 return;
108 }
109 for (auto& callback : jsCallBack_[methodName]) {
110 napi_value method = callback->GetNapiValue();
111 if (method == nullptr) {
112 TLOGE(WmsLogTag::DMS, "Failed to get method callback from object");
113 continue;
114 }
115 napi_call_function(env_, NapiGetUndefined(env_), method, argc, argv, nullptr);
116 }
117 }
118
OnCreate(DisplayId id)119 void JsDisplayListener::OnCreate(DisplayId id)
120 {
121 std::lock_guard<std::mutex> lock(mtx_);
122 TLOGI(WmsLogTag::DMS, "called, displayId: %{public}d", static_cast<uint32_t>(id));
123 if (jsCallBack_.empty()) {
124 TLOGE(WmsLogTag::DMS, "not register!");
125 return;
126 }
127 if (jsCallBack_.find(EVENT_ADD) == jsCallBack_.end()) {
128 TLOGE(WmsLogTag::DMS, "not this event, return");
129 return;
130 }
131 auto napiTask = [self = weakRef_, id, env = env_]() {
132 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsDisplayListener::OnCreate");
133 auto thisListener = self.promote();
134 if (thisListener == nullptr || env == nullptr) {
135 TLOGNE(WmsLogTag::DMS, "[NAPI]this listener or env is nullptr");
136 return;
137 }
138 napi_value argv[] = {CreateJsValue(env, static_cast<uint32_t>(id))};
139 thisListener->CallJsMethod(EVENT_ADD, argv, ArraySize(argv));
140 };
141
142 if (env_ != nullptr) {
143 napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate, "OnCreate");
144 if (ret != napi_status::napi_ok) {
145 TLOGE(WmsLogTag::DMS, "Failed to SendEvent.");
146 }
147 } else {
148 TLOGE(WmsLogTag::DMS, "env is nullptr");
149 }
150 }
151
OnDestroy(DisplayId id)152 void JsDisplayListener::OnDestroy(DisplayId id)
153 {
154 std::lock_guard<std::mutex> lock(mtx_);
155 TLOGI(WmsLogTag::DMS, "called, displayId: %{public}d", static_cast<uint32_t>(id));
156 if (jsCallBack_.empty()) {
157 TLOGE(WmsLogTag::DMS, "not register!");
158 return;
159 }
160 if (jsCallBack_.find(EVENT_REMOVE) == jsCallBack_.end()) {
161 TLOGE(WmsLogTag::DMS, "not this event, return");
162 return;
163 }
164 auto napiTask = [self = weakRef_, id, env = env_]() {
165 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsDisplayListener::OnDestroy");
166 auto thisListener = self.promote();
167 if (thisListener == nullptr || env == nullptr) {
168 TLOGNE(WmsLogTag::DMS, "[NAPI]this listener or env is nullptr");
169 return;
170 }
171 napi_value argv[] = {CreateJsValue(env, static_cast<uint32_t>(id))};
172 thisListener->CallJsMethod(EVENT_REMOVE, argv, ArraySize(argv));
173 };
174
175 if (env_ != nullptr) {
176 napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate, "OnDestroy");
177 if (ret != napi_status::napi_ok) {
178 TLOGE(WmsLogTag::DMS, "OFailed to SendEvent.");
179 }
180 } else {
181 TLOGE(WmsLogTag::DMS, " env is nullptr");
182 }
183 }
184
OnChange(DisplayId id)185 void JsDisplayListener::OnChange(DisplayId id)
186 {
187 std::lock_guard<std::mutex> lock(mtx_);
188 TLOGD(WmsLogTag::DMS, "Jcalled, displayId: %{public}d", static_cast<uint32_t>(id));
189 if (jsCallBack_.empty()) {
190 TLOGE(WmsLogTag::DMS, "not register!");
191 return;
192 }
193 if (jsCallBack_.find(EVENT_CHANGE) == jsCallBack_.end()) {
194 TLOGD(WmsLogTag::DMS, "not this event, return");
195 return;
196 }
197 auto napiTask = [self = weakRef_, id, env = env_]() {
198 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsDisplayListener::OnChange");
199 auto thisListener = self.promote();
200 if (thisListener == nullptr || env == nullptr) {
201 TLOGNE(WmsLogTag::DMS, "[NAPI]this listener or env is nullptr");
202 return;
203 }
204 napi_value argv[] = {CreateJsValue(env, static_cast<uint32_t>(id))};
205 thisListener->CallJsMethod(EVENT_CHANGE, argv, ArraySize(argv));
206 };
207
208 if (env_ != nullptr) {
209 napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate, "OnChange");
210 if (ret != napi_status::napi_ok) {
211 TLOGE(WmsLogTag::DMS, "Failed to SendEvent.");
212 }
213 } else {
214 TLOGE(WmsLogTag::DMS, "env is nullptr");
215 }
216 }
217
OnPrivateWindow(bool hasPrivate)218 void JsDisplayListener::OnPrivateWindow(bool hasPrivate)
219 {
220 std::lock_guard<std::mutex> lock(mtx_);
221 TLOGI(WmsLogTag::DMS, "called, private status: %{public}u", static_cast<uint32_t>(hasPrivate));
222 if (jsCallBack_.empty()) {
223 TLOGE(WmsLogTag::DMS, "not register!");
224 return;
225 }
226 if (jsCallBack_.find(EVENT_PRIVATE_MODE_CHANGE) == jsCallBack_.end()) {
227 TLOGE(WmsLogTag::DMS, "OnPrivateWindow not this event, return");
228 return;
229 }
230 auto napiTask = [self = weakRef_, hasPrivate, env = env_]() {
231 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsDisplayListener::OnPrivateWindow");
232 auto thisListener = self.promote();
233 if (thisListener == nullptr || env == nullptr) {
234 TLOGNE(WmsLogTag::DMS, "[NAPI]this listener or env is nullptr");
235 return;
236 }
237 napi_value argv[] = {CreateJsValue(env, hasPrivate)};
238 thisListener->CallJsMethod(EVENT_PRIVATE_MODE_CHANGE, argv, ArraySize(argv));
239 };
240
241 if (env_ != nullptr) {
242 napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate, "OnPrivateWindow");
243 if (ret != napi_status::napi_ok) {
244 TLOGE(WmsLogTag::DMS, "Failed to SendEvent.");
245 }
246 } else {
247 TLOGE(WmsLogTag::DMS, "env is nullptr");
248 }
249 }
250
OnFoldStatusChanged(FoldStatus foldStatus)251 void JsDisplayListener::OnFoldStatusChanged(FoldStatus foldStatus)
252 {
253 std::lock_guard<std::mutex> lock(mtx_);
254 TLOGI(WmsLogTag::DMS, "called, foldStatus: %{public}u", static_cast<uint32_t>(foldStatus));
255 if (jsCallBack_.empty()) {
256 TLOGE(WmsLogTag::DMS, "not register!");
257 return;
258 }
259 if (jsCallBack_.find(EVENT_FOLD_STATUS_CHANGED) == jsCallBack_.end()) {
260 TLOGE(WmsLogTag::DMS, "not this event, return");
261 return;
262 }
263 auto napiTask = [self = weakRef_, foldStatus, env = env_] () {
264 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsDisplayListener::OnFoldStatusChanged");
265 auto thisListener = self.promote();
266 if (thisListener == nullptr || env == nullptr) {
267 TLOGNE(WmsLogTag::DMS, "[NAPI]this listener or env is nullptr");
268 return;
269 }
270 napi_value argv[] = {CreateJsValue(env, foldStatus)};
271 thisListener->CallJsMethod(EVENT_FOLD_STATUS_CHANGED, argv, ArraySize(argv));
272 };
273
274 if (env_ != nullptr) {
275 napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate, "OnFoldStatusChanged");
276 if (ret != napi_status::napi_ok) {
277 TLOGE(WmsLogTag::DMS, "Failed to SendEvent.");
278 }
279 } else {
280 TLOGE(WmsLogTag::DMS, "env is nullptr");
281 }
282 }
283
OnFoldAngleChanged(std::vector<float> foldAngles)284 void JsDisplayListener::OnFoldAngleChanged(std::vector<float> foldAngles)
285 {
286 std::lock_guard<std::mutex> lock(mtx_);
287 if (jsCallBack_.empty()) {
288 TLOGE(WmsLogTag::DMS, "not register!");
289 return;
290 }
291 if (jsCallBack_.find(EVENT_FOLD_ANGLE_CHANGED) == jsCallBack_.end()) {
292 TLOGE(WmsLogTag::DMS, "not this event, return");
293 return;
294 }
295 auto napiTask = [self = weakRef_, foldAngles, env = env_]() {
296 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsDisplayListener::OnFoldAngleChanged");
297 auto thisListener = self.promote();
298 if (thisListener == nullptr || env == nullptr) {
299 TLOGNE(WmsLogTag::DMS, "[NAPI]this listener or env is nullptr");
300 return;
301 }
302 napi_value argv[] = {CreateNativeArray(env, foldAngles)};
303 thisListener->CallJsMethod(EVENT_FOLD_ANGLE_CHANGED, argv, ArraySize(argv));
304 };
305
306 if (env_ != nullptr) {
307 napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate, "OnFoldAngleChanged");
308 if (ret != napi_status::napi_ok) {
309 TLOGE(WmsLogTag::DMS, "Failed to SendEvent.");
310 }
311 } else {
312 TLOGE(WmsLogTag::DMS, "env is nullptr");
313 }
314 }
315
OnCaptureStatusChanged(bool isCapture)316 void JsDisplayListener::OnCaptureStatusChanged(bool isCapture)
317 {
318 std::lock_guard<std::mutex> lock(mtx_);
319 if (jsCallBack_.empty()) {
320 TLOGE(WmsLogTag::DMS, "not register!");
321 return;
322 }
323 if (jsCallBack_.find(EVENT_CAPTURE_STATUS_CHANGED) == jsCallBack_.end()) {
324 TLOGE(WmsLogTag::DMS, "not this event, return");
325 return;
326 }
327 auto napiTask = [self = weakRef_, isCapture, env = env_]() {
328 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsDisplayListener::OnCaptureStatusChanged");
329 auto thisListener = self.promote();
330 if (thisListener == nullptr || env == nullptr) {
331 TLOGNE(WmsLogTag::DMS, "[NAPI]this listener or env is nullptr");
332 return;
333 }
334 napi_value argv[] = {CreateJsValue(env, isCapture)};
335 thisListener->CallJsMethod(EVENT_CAPTURE_STATUS_CHANGED, argv, ArraySize(argv));
336 };
337
338 if (env_ != nullptr) {
339 napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate, "OnCaptureStatusChanged");
340 if (ret != napi_status::napi_ok) {
341 TLOGE(WmsLogTag::DMS, "Failed to SendEvent.");
342 }
343 } else {
344 TLOGE(WmsLogTag::DMS, "env is nullptr");
345 }
346 }
347
OnDisplayModeChanged(FoldDisplayMode displayMode)348 void JsDisplayListener::OnDisplayModeChanged(FoldDisplayMode displayMode)
349 {
350 std::lock_guard<std::mutex> lock(mtx_);
351 TLOGI(WmsLogTag::DMS, "called, displayMode: %{public}u", static_cast<uint32_t>(displayMode));
352 if (jsCallBack_.empty()) {
353 TLOGE(WmsLogTag::DMS, "not register!");
354 return;
355 }
356 if (jsCallBack_.find(EVENT_DISPLAY_MODE_CHANGED) == jsCallBack_.end()) {
357 TLOGE(WmsLogTag::DMS, "not this event, return");
358 return;
359 }
360 auto napiTask = [self = weakRef_, displayMode, env = env_] () {
361 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsDisplayListener::OnDisplayModeChanged");
362 auto thisListener = self.promote();
363 if (thisListener == nullptr || env == nullptr) {
364 TLOGNE(WmsLogTag::DMS, "[NAPI]this listener or env is nullptr");
365 return;
366 }
367 napi_value argv[] = {CreateJsValue(env, displayMode)};
368 thisListener->CallJsMethod(EVENT_DISPLAY_MODE_CHANGED, argv, ArraySize(argv));
369 };
370
371 if (env_ != nullptr) {
372 napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate, "OnDisplayModeChanged");
373 if (ret != napi_status::napi_ok) {
374 TLOGE(WmsLogTag::DMS, "Failed to SendEvent.");
375 }
376 } else {
377 TLOGE(WmsLogTag::DMS, "env is nullptr");
378 }
379 }
380
OnAvailableAreaChanged(DMRect area)381 void JsDisplayListener::OnAvailableAreaChanged(DMRect area)
382 {
383 std::lock_guard<std::mutex> lock(mtx_);
384 TLOGI(WmsLogTag::DMS, "called");
385 if (jsCallBack_.empty()) {
386 TLOGE(WmsLogTag::DMS, "not register!");
387 return;
388 }
389 if (jsCallBack_.find(EVENT_AVAILABLE_AREA_CHANGED) == jsCallBack_.end()) {
390 TLOGE(WmsLogTag::DMS, "not this event, return");
391 return;
392 }
393 auto napiTask = [self = weakRef_, area, env = env_]() {
394 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsDisplayListener::OnAvailableAreaChanged");
395 auto thisListener = self.promote();
396 if (thisListener == nullptr || env == nullptr) {
397 TLOGNE(WmsLogTag::DMS, "[NAPI]this listener or env is nullptr");
398 return;
399 }
400 napi_value argv[] = {CreateJsRectObject(env, area)};
401 thisListener->CallJsMethod(EVENT_AVAILABLE_AREA_CHANGED, argv, ArraySize(argv));
402 };
403
404 if (env_ != nullptr) {
405 napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate, "OnAvailableAreaChanged");
406 if (ret != napi_status::napi_ok) {
407 TLOGE(WmsLogTag::DMS, "Failed to SendEvent.");
408 }
409 } else {
410 TLOGE(WmsLogTag::DMS, "env is nullptr");
411 }
412 }
413 } // namespace Rosen
414 } // namespace OHOS
415