1 /*
2 * Copyright (c) 2023-2023 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_extension_window_register_manager.h"
17 #include "singleton_container.h"
18 #include "window_manager.h"
19 #include "window_manager_hilog.h"
20
21 namespace OHOS {
22 namespace Rosen {
23 namespace {
24 const std::string WINDOW_SIZE_CHANGE_CB = "windowSizeChange";
25 const std::string WINDOW_RECT_CHANGE_CB = "rectChange";
26 const std::string AVOID_AREA_CHANGE_CB = "avoidAreaChange";
27 const std::string WINDOW_STAGE_EVENT_CB = "windowStageEvent";
28 const std::string WINDOW_EVENT_CB = "windowEvent";
29 }
30
JsExtensionWindowRegisterManager()31 JsExtensionWindowRegisterManager::JsExtensionWindowRegisterManager()
32 {
33 // white register list for window
34 listenerCodeMap_[CaseType::CASE_WINDOW] = {
35 {WINDOW_SIZE_CHANGE_CB, ListenerType::WINDOW_SIZE_CHANGE_CB},
36 {WINDOW_RECT_CHANGE_CB, ListenerType::WINDOW_RECT_CHANGE_CB},
37 {AVOID_AREA_CHANGE_CB, ListenerType::AVOID_AREA_CHANGE_CB},
38 {WINDOW_EVENT_CB, ListenerType::WINDOW_EVENT_CB},
39 };
40 // white register list for window stage
41 listenerCodeMap_[CaseType::CASE_STAGE] = {
42 {WINDOW_STAGE_EVENT_CB, ListenerType::WINDOW_STAGE_EVENT_CB}
43 };
44 }
45
~JsExtensionWindowRegisterManager()46 JsExtensionWindowRegisterManager::~JsExtensionWindowRegisterManager()
47 {
48 }
49
ProcessWindowChangeRegister(sptr<JsExtensionWindowListener> listener,sptr<Window> window,bool isRegister)50 WmErrorCode JsExtensionWindowRegisterManager::ProcessWindowChangeRegister(sptr<JsExtensionWindowListener> listener,
51 sptr<Window> window, bool isRegister)
52 {
53 if (window == nullptr) {
54 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Window is nullptr");
55 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
56 }
57 sptr<IWindowChangeListener> thisListener(listener);
58 WmErrorCode ret = WmErrorCode::WM_OK;
59 if (isRegister) {
60 ret = WM_JS_TO_ERROR_CODE_MAP.at(window->RegisterWindowChangeListener(thisListener));
61 } else {
62 ret = WM_JS_TO_ERROR_CODE_MAP.at(window->UnregisterWindowChangeListener(thisListener));
63 }
64 return ret;
65 }
66
ProcessWindowRectChangeRegister(const sptr<JsExtensionWindowListener> & listener,const sptr<Window> & window,bool isRegister)67 WmErrorCode JsExtensionWindowRegisterManager::ProcessWindowRectChangeRegister(
68 const sptr<JsExtensionWindowListener>& listener, const sptr<Window>& window, bool isRegister)
69 {
70 if (window == nullptr) {
71 TLOGE(WmsLogTag::WMS_UIEXT, "Window is nullptr");
72 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
73 }
74 return isRegister ?
75 WM_JS_TO_ERROR_CODE_MAP.at(window->RegisterWindowRectChangeListener(listener)) :
76 WM_JS_TO_ERROR_CODE_MAP.at(window->UnregisterWindowRectChangeListener(listener));
77 }
78
ProcessAvoidAreaChangeRegister(sptr<JsExtensionWindowListener> listener,sptr<Window> window,bool isRegister)79 WmErrorCode JsExtensionWindowRegisterManager::ProcessAvoidAreaChangeRegister(sptr<JsExtensionWindowListener> listener,
80 sptr<Window> window, bool isRegister)
81 {
82 if (window == nullptr) {
83 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Window is nullptr");
84 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
85 }
86 sptr<IAvoidAreaChangedListener> thisListener(listener);
87 WmErrorCode ret = WmErrorCode::WM_OK;
88 if (isRegister) {
89 ret = WM_JS_TO_ERROR_CODE_MAP.at(window->RegisterAvoidAreaChangeListener(thisListener));
90 } else {
91 ret = WM_JS_TO_ERROR_CODE_MAP.at(window->UnregisterAvoidAreaChangeListener(thisListener));
92 }
93 return ret;
94 }
95
ProcessLifeCycleEventRegister(sptr<JsExtensionWindowListener> listener,sptr<Window> window,bool isRegister)96 WmErrorCode JsExtensionWindowRegisterManager::ProcessLifeCycleEventRegister(sptr<JsExtensionWindowListener> listener,
97 sptr<Window> window, bool isRegister)
98 {
99 if (window == nullptr) {
100 TLOGE(WmsLogTag::WMS_UIEXT, "Window is nullptr");
101 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
102 }
103 sptr<IWindowLifeCycle> thisListener(listener);
104 WmErrorCode ret = WmErrorCode::WM_OK;
105 if (isRegister) {
106 ret = WM_JS_TO_ERROR_CODE_MAP.at(window->RegisterLifeCycleListener(thisListener));
107 } else {
108 ret = WM_JS_TO_ERROR_CODE_MAP.at(window->UnregisterLifeCycleListener(thisListener));
109 }
110 return ret;
111 }
112
IsCallbackRegistered(napi_env env,std::string type,napi_value jsListenerObject)113 bool JsExtensionWindowRegisterManager::IsCallbackRegistered(napi_env env, std::string type, napi_value jsListenerObject)
114 {
115 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
116 TLOGI(WmsLogTag::WMS_UIEXT, "[NAPI]Method %{public}s has not been registered", type.c_str());
117 return false;
118 }
119
120 for (auto iter = jsCbMap_[type].begin(); iter != jsCbMap_[type].end(); ++iter) {
121 bool isEquals = false;
122 napi_strict_equals(env, jsListenerObject, iter->first->GetNapiValue(), &isEquals);
123 if (isEquals) {
124 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Method %{public}s has already been registered", type.c_str());
125 return true;
126 }
127 }
128 return false;
129 }
130
RegisterListener(sptr<Window> window,std::string type,CaseType caseType,napi_env env,napi_value value)131 WmErrorCode JsExtensionWindowRegisterManager::RegisterListener(sptr<Window> window, std::string type,
132 CaseType caseType, napi_env env, napi_value value)
133 {
134 std::lock_guard<std::mutex> lock(mtx_);
135 if (IsCallbackRegistered(env, type, value)) {
136 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
137 }
138 if (listenerCodeMap_[caseType].count(type) == 0) {
139 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Type %{public}s is not supported", type.c_str());
140 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
141 }
142 napi_ref result = nullptr;
143 napi_create_reference(env, value, 1, &result);
144 std::shared_ptr<NativeReference> callbackRef(reinterpret_cast<NativeReference*>(result));
145 sptr<JsExtensionWindowListener> extensionWindowListener =
146 new(std::nothrow) JsExtensionWindowListener(env, callbackRef);
147 if (extensionWindowListener == nullptr) {
148 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]New JsExtensionWindowListener failed");
149 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
150 }
151 extensionWindowListener->SetMainEventHandler();
152 WmErrorCode ret = ProcessRegister(caseType, extensionWindowListener, window, type, true);
153 if (ret != WmErrorCode::WM_OK) {
154 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Register type %{public}s failed", type.c_str());
155 return ret;
156 }
157 jsCbMap_[type][callbackRef] = extensionWindowListener;
158 TLOGI(WmsLogTag::WMS_UIEXT, "[NAPI]Register type %{public}s success! callback map size: %{public}zu", type.c_str(),
159 jsCbMap_[type].size());
160 return WmErrorCode::WM_OK;
161 }
162
UnregisterListener(sptr<Window> window,std::string type,CaseType caseType,napi_env env,napi_value value)163 WmErrorCode JsExtensionWindowRegisterManager::UnregisterListener(sptr<Window> window, std::string type,
164 CaseType caseType, napi_env env, napi_value value)
165 {
166 std::lock_guard<std::mutex> lock(mtx_);
167 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
168 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Type %{public}s was not registered", type.c_str());
169 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
170 }
171 if (listenerCodeMap_[caseType].count(type) == 0) {
172 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Type %{public}s is not supported", type.c_str());
173 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
174 }
175 if (value == nullptr) {
176 for (auto it = jsCbMap_[type].begin(); it != jsCbMap_[type].end();) {
177 WmErrorCode ret = ProcessRegister(caseType, it->second, window, type, false);
178 if (ret != WmErrorCode::WM_OK) {
179 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Unregister type %{public}s failed, no value", type.c_str());
180 return ret;
181 }
182 jsCbMap_[type].erase(it++);
183 }
184 } else {
185 bool findFlag = false;
186 for (auto it = jsCbMap_[type].begin(); it != jsCbMap_[type].end(); ++it) {
187 bool isEquals = false;
188 napi_strict_equals(env, value, it->first->GetNapiValue(), &isEquals);
189 if (!isEquals) {
190 continue;
191 }
192 findFlag = true;
193 WmErrorCode ret = ProcessRegister(caseType, it->second, window, type, false);
194 if (ret != WmErrorCode::WM_OK) {
195 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Unregister type %{public}s failed", type.c_str());
196 return ret;
197 }
198 jsCbMap_[type].erase(it);
199 break;
200 }
201 if (!findFlag) {
202 TLOGE(WmsLogTag::WMS_UIEXT,
203 "[NAPI]Unregister type %{public}s failed because not found callback!", type.c_str());
204 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
205 }
206 }
207 TLOGI(WmsLogTag::WMS_UIEXT, "[NAPI]Unregister type %{public}s success! callback map size: %{public}zu",
208 type.c_str(), jsCbMap_[type].size());
209 // erase type when there is no callback in one type
210 if (jsCbMap_[type].empty()) {
211 jsCbMap_.erase(type);
212 }
213 return WmErrorCode::WM_OK;
214 }
215
ProcessRegister(CaseType caseType,const sptr<JsExtensionWindowListener> & listener,const sptr<Window> & window,const std::string & type,bool isRegister)216 WmErrorCode JsExtensionWindowRegisterManager::ProcessRegister(CaseType caseType,
217 const sptr<JsExtensionWindowListener>& listener, const sptr<Window>& window, const std::string& type,
218 bool isRegister)
219 {
220 WmErrorCode ret = WmErrorCode::WM_OK;
221 if (caseType == CaseType::CASE_WINDOW) {
222 switch (listenerCodeMap_[caseType][type]) {
223 case ListenerType::WINDOW_SIZE_CHANGE_CB:
224 ret = ProcessWindowChangeRegister(listener, window, isRegister);
225 break;
226 case ListenerType::WINDOW_RECT_CHANGE_CB:
227 ret = ProcessWindowRectChangeRegister(listener, window, isRegister);
228 break;
229 case ListenerType::AVOID_AREA_CHANGE_CB:
230 ret = ProcessAvoidAreaChangeRegister(listener, window, isRegister);
231 break;
232 case ListenerType::WINDOW_EVENT_CB:
233 ret = ProcessLifeCycleEventRegister(listener, window, isRegister);
234 break;
235 default:
236 break;
237 }
238 } else if (caseType == CaseType::CASE_STAGE) {
239 if (type == WINDOW_STAGE_EVENT_CB) {
240 ret = ProcessLifeCycleEventRegister(listener, window, isRegister);
241 }
242 }
243 return ret;
244 }
245
246 } // namespace Rosen
247 } // namespace OHOS