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