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