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 #include "js_screen_listener.h"
16 #include "js_runtime_utils.h"
17 #include "window_manager_hilog.h"
18 #include "js_screen.h"
19
20 namespace OHOS {
21 namespace Rosen {
22 using namespace AbilityRuntime;
23 namespace {
24 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "JsScreenListener"};
25 }
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)
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 WLOGI("JsScreenListener::AddCallback is 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 WLOGI("JsScreenListener::AddCallback 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 WLOGE("JsScreenListener::RemoveCallback 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 WLOGI("JsScreenListener::RemoveCallback 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 WLOGFE("empty method name str, call method failed");
98 return;
99 }
100 WLOGD("CallJsMethod methodName = %{public}s", methodName.c_str());
101 if (env_ == nullptr) {
102 WLOGFE("env_ nullptr");
103 return;
104 }
105 for (auto& callback : jsCallBack_[methodName]) {
106 napi_value method = callback->GetNapiValue();
107 if (method == nullptr) {
108 WLOGFE("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 WLOGI("JsScreenListener::OnConnect is called");
119 if (jsCallBack_.empty()) {
120 WLOGFE("JsScreenListener::OnConnect not register!");
121 return;
122 }
123 if (jsCallBack_.find(EVENT_CONNECT) == jsCallBack_.end()) {
124 WLOGE("JsScreenListener::OnConnect not this event, return");
125 return;
126 }
127 sptr<JsScreenListener> listener = this; // Avoid this be destroyed when using.
128 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback> (
129 [this, listener, id] (napi_env env, NapiAsyncTask &task, int32_t status) {
130 napi_value argv[] = {CreateJsValue(env_, static_cast<uint32_t>(id))};
131 CallJsMethod(EVENT_CONNECT, argv, ArraySize(argv));
132 }
133 );
134
135 napi_ref callback = nullptr;
136 std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
137 NapiAsyncTask::Schedule("JsScreenListener::OnConnect", env_, std::make_unique<NapiAsyncTask>(
138 callback, std::move(execute), std::move(complete)));
139 }
140
OnDisconnect(ScreenId id)141 void JsScreenListener::OnDisconnect(ScreenId id)
142 {
143 std::lock_guard<std::mutex> lock(mtx_);
144 WLOGI("JsScreenListener::OnDisconnect is called");
145 if (jsCallBack_.empty()) {
146 WLOGFE("JsScreenListener::OnDisconnect not register!");
147 return;
148 }
149 if (jsCallBack_.find(EVENT_DISCONNECT) == jsCallBack_.end()) {
150 WLOGE("JsScreenListener::OnDisconnect not this event, return");
151 return;
152 }
153 sptr<JsScreenListener> listener = this; // Avoid this be destroyed when using.
154 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback> (
155 [this, listener, id] (napi_env env, NapiAsyncTask &task, int32_t status) {
156 napi_value argv[] = {CreateJsValue(env_, static_cast<uint32_t>(id))};
157 CallJsMethod(EVENT_DISCONNECT, argv, ArraySize(argv));
158 }
159 );
160
161 napi_ref callback = nullptr;
162 std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
163 NapiAsyncTask::Schedule("JsScreenListener::OnDisconnect", env_, std::make_unique<NapiAsyncTask>(
164 callback, std::move(execute), std::move(complete)));
165 }
166
OnChange(ScreenId id)167 void JsScreenListener::OnChange(ScreenId id)
168 {
169 std::lock_guard<std::mutex> lock(mtx_);
170 WLOGI("JsScreenListener::OnChange is called");
171 if (jsCallBack_.empty()) {
172 WLOGFE("JsScreenListener::OnChange not register!");
173 return;
174 }
175 if (jsCallBack_.find(EVENT_CHANGE) == jsCallBack_.end()) {
176 WLOGE("JsScreenListener::OnChange not this event, return");
177 return;
178 }
179 sptr<JsScreenListener> listener = this; // Avoid this be destroyed when using.
180 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback> (
181 [this, listener, id] (napi_env env, NapiAsyncTask &task, int32_t status) {
182 napi_value argv[] = {CreateJsValue(env_, static_cast<uint32_t>(id))};
183 CallJsMethod(EVENT_CHANGE, argv, ArraySize(argv));
184 }
185 );
186
187 napi_ref callback = nullptr;
188 std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
189 NapiAsyncTask::Schedule("JsScreenListener::OnChange", env_, std::make_unique<NapiAsyncTask>(
190 callback, std::move(execute), std::move(complete)));
191 }
192
CreateScreenIdArray(napi_env env,const std::vector<ScreenId> & data)193 napi_value JsScreenListener::CreateScreenIdArray(napi_env env, const std::vector<ScreenId>& data)
194 {
195 napi_value arrayValue = nullptr;
196 napi_create_array_with_length(env, data.size(), &arrayValue);
197 if (arrayValue == nullptr) {
198 WLOGFE("Failed to create screenid array");
199 return NapiGetUndefined(env);
200 }
201 uint32_t index = 0;
202 for (const auto& item : data) {
203 napi_set_element(env, arrayValue, index++, CreateJsValue(env, static_cast<uint32_t>(item)));
204 }
205 return arrayValue;
206 }
207 } // namespace Rosen
208 } // namespace OHOS
209