1 /*
2 * Copyright (c) 2022-2024 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_window_register_manager.h"
16 #include "window_manager_hilog.h"
17
18 namespace OHOS {
19 namespace Rosen {
20 namespace {
21 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "JsRegisterManager"};
22
23 const std::map<std::string, ListenerFunctionType> WindowListenerFunctionMap {
24 {SYSTEM_AVOID_AREA_CHANGE_CB, ListenerFunctionType::SYSTEM_AVOID_AREA_CHANGE_CB},
25 {AVOID_AREA_CHANGE_CB, ListenerFunctionType::AVOID_AREA_CHANGE_CB},
26 };
27
28 const std::map<CaseType, std::map<std::string, ListenerFunctionType>> ListenerFunctionMap {
29 {CaseType::CASE_WINDOW, WindowListenerFunctionMap},
30 };
31 }
32
JsWindowRegisterManager()33 JsWindowRegisterManager::JsWindowRegisterManager()
34 {
35 }
36
~JsWindowRegisterManager()37 JsWindowRegisterManager::~JsWindowRegisterManager()
38 {
39 }
40
ProcessSystemAvoidAreaChangeRegister(sptr<JsWindowListener> listener,sptr<Window> window,bool isRegister,napi_env env,napi_value parameter)41 WmErrorCode JsWindowRegisterManager::ProcessSystemAvoidAreaChangeRegister(sptr<JsWindowListener> listener,
42 sptr<Window> window, bool isRegister, napi_env env, napi_value parameter)
43 {
44 if (window == nullptr) {
45 WLOGFE("[NAPI]Window is nullptr");
46 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
47 }
48 if (listener == nullptr) {
49 WLOGFE("[NAPI]listener is nullptr");
50 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
51 }
52 listener->SetIsDeprecatedInterface(true);
53 sptr<IAvoidAreaChangedListener> thisListener(listener);
54 WmErrorCode ret;
55 if (isRegister) {
56 ret = WM_JS_TO_ERROR_CODE_MAP.at(window->RegisterAvoidAreaChangeListener(thisListener));
57 } else {
58 ret = WM_JS_TO_ERROR_CODE_MAP.at(window->UnregisterAvoidAreaChangeListener(thisListener));
59 }
60 return ret;
61 }
62
ProcessAvoidAreaChangeRegister(sptr<JsWindowListener> listener,sptr<Window> window,bool isRegister,napi_env env,napi_value parameter)63 WmErrorCode JsWindowRegisterManager::ProcessAvoidAreaChangeRegister(sptr<JsWindowListener> listener,
64 sptr<Window> window, bool isRegister, napi_env env, napi_value parameter)
65 {
66 if (window == nullptr) {
67 WLOGFE("[NAPI]Window is nullptr");
68 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
69 }
70 sptr<IAvoidAreaChangedListener> thisListener(listener);
71 WmErrorCode ret;
72 if (isRegister) {
73 ret = WM_JS_TO_ERROR_CODE_MAP.at(window->RegisterAvoidAreaChangeListener(thisListener));
74 } else {
75 ret = WM_JS_TO_ERROR_CODE_MAP.at(window->UnregisterAvoidAreaChangeListener(thisListener));
76 }
77 return ret;
78 }
79
RegisterListener(sptr<Window> window,std::string type,CaseType caseType,napi_env env,napi_value callback,napi_value parameter)80 WmErrorCode JsWindowRegisterManager::RegisterListener(sptr<Window> window, std::string type,
81 CaseType caseType, napi_env env, napi_value callback, napi_value parameter)
82 {
83 std::lock_guard<std::mutex> lock(mtx_);
84 if (IsCallbackRegistered(env, type, callback)) {
85 return WmErrorCode::WM_OK;
86 }
87 auto iterCaseType = ListenerFunctionMap.find(caseType);
88 if (iterCaseType == ListenerFunctionMap.end()) {
89 WLOGFE("[NAPI]CaseType %{public}u is not supported", static_cast<uint32_t>(caseType));
90 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
91 }
92 auto iterCallbackType = iterCaseType->second.find(type);
93 if (iterCallbackType == iterCaseType->second.end()) {
94 WLOGFE("[NAPI]Type %{public}s is not supported", type.c_str());
95 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
96 }
97 ListenerFunctionType listenerFunctionType = iterCallbackType->second;
98 napi_ref result = nullptr;
99 napi_create_reference(env, callback, 1, &result);
100 std::shared_ptr<NativeReference> callbackRef(reinterpret_cast<NativeReference*>(result));
101 sptr<JsWindowListener> windowManagerListener = new(std::nothrow) JsWindowListener(env, callbackRef);
102 if (windowManagerListener == nullptr) {
103 WLOGFE("[NAPI]New JsWindowListener failed");
104 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
105 }
106 windowManagerListener->SetMainEventHandler();
107 WmErrorCode ret = ProcessRegisterCallback(listenerFunctionType, caseType, windowManagerListener, window,
108 true, env, parameter);
109 if (ret != WmErrorCode::WM_OK) {
110 WLOGFE("[NAPI]Register type %{public}s failed", type.c_str());
111 return ret;
112 }
113 jsCbMap_[type][callbackRef] = windowManagerListener;
114 WLOGI("[NAPI]Register type %{public}s success! callback map size: %{public}zu",
115 type.c_str(), jsCbMap_[type].size());
116 return WmErrorCode::WM_OK;
117 }
118
ProcessRegisterCallback(ListenerFunctionType listenerFunctionType,CaseType caseType,const sptr<JsWindowListener> & listener,const sptr<Window> & window,bool isRegister,napi_env env,napi_value parameter)119 WmErrorCode JsWindowRegisterManager::ProcessRegisterCallback(ListenerFunctionType listenerFunctionType,
120 CaseType caseType, const sptr<JsWindowListener>& listener, const sptr<Window>& window, bool isRegister,
121 napi_env env, napi_value parameter)
122 {
123 if (caseType == CaseType::CASE_WINDOW) {
124 switch (listenerFunctionType) {
125 case ListenerFunctionType::SYSTEM_AVOID_AREA_CHANGE_CB:
126 return ProcessSystemAvoidAreaChangeRegister(listener, window, isRegister, env, parameter);
127 case ListenerFunctionType::AVOID_AREA_CHANGE_CB:
128 return ProcessAvoidAreaChangeRegister(listener, window, isRegister, env, parameter);
129 default:
130 return WmErrorCode::WM_ERROR_INVALID_PARAM;
131 }
132 }
133 return WmErrorCode::WM_ERROR_INVALID_PARAM;
134 }
135
UnregisterListener(sptr<Window> window,std::string type,CaseType caseType,napi_env env,napi_value value)136 WmErrorCode JsWindowRegisterManager::UnregisterListener(sptr<Window> window, std::string type,
137 CaseType caseType, napi_env env, napi_value value)
138 {
139 std::lock_guard<std::mutex> lock(mtx_);
140 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
141 WLOGFE("[NAPI]Type %{public}s was not registerted", type.c_str());
142 return WmErrorCode::WM_OK;
143 }
144 auto iterCaseType = ListenerFunctionMap.find(caseType);
145 if (iterCaseType == ListenerFunctionMap.end()) {
146 WLOGFE("[NAPI]CaseType %{public}u is not supported", static_cast<uint32_t>(caseType));
147 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
148 }
149 auto iterCallbackType = iterCaseType->second.find(type);
150 if (iterCallbackType == iterCaseType->second.end()) {
151 WLOGFE("[NAPI]Type %{public}s is not supported", type.c_str());
152 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
153 }
154 ListenerFunctionType listenerFunctionType = iterCallbackType->second;
155 if (value == nullptr) {
156 for (auto it = jsCbMap_[type].begin(); it != jsCbMap_[type].end();) {
157 WmErrorCode ret = ProcessRegisterCallback(listenerFunctionType, caseType, it->second, window, false,
158 env, nullptr);
159 if (ret != WmErrorCode::WM_OK) {
160 WLOGFE("[NAPI]Unregister type %{public}s failed, no value", type.c_str());
161 return ret;
162 }
163 jsCbMap_[type].erase(it++);
164 }
165 } else {
166 bool findFlag = false;
167 for (auto it = jsCbMap_[type].begin(); it != jsCbMap_[type].end(); ++it) {
168 bool isEquals = false;
169 napi_strict_equals(env, value, it->first->GetNapiValue(), &isEquals);
170 if (!isEquals) {
171 continue;
172 }
173 findFlag = true;
174 WmErrorCode ret = ProcessRegisterCallback(listenerFunctionType, caseType, it->second, window, false,
175 env, nullptr);
176 if (ret != WmErrorCode::WM_OK) {
177 WLOGFE("[NAPI]Unregister type %{public}s failed", type.c_str());
178 return ret;
179 }
180 jsCbMap_[type].erase(it);
181 break;
182 }
183 if (!findFlag) {
184 WLOGFE("[NAPI]Unregister type %{public}s failed because not found callback!", type.c_str());
185 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
186 }
187 }
188 WLOGI("[NAPI]Unregister type %{public}s success! callback map size: %{public}zu",
189 type.c_str(), jsCbMap_[type].size());
190 // erase type when there is no callback in one type
191 if (jsCbMap_[type].empty()) {
192 jsCbMap_.erase(type);
193 }
194 return WmErrorCode::WM_OK;
195 }
196
IsCallbackRegistered(napi_env env,std::string & type,napi_value jsListenerObject)197 bool JsWindowRegisterManager::IsCallbackRegistered(napi_env env, std::string& type, napi_value jsListenerObject)
198 {
199 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
200 WLOGI("[NAPI]Method %{public}s has not been registerted", type.c_str());
201 return false;
202 }
203
204 for (auto iter = jsCbMap_[type].begin(); iter != jsCbMap_[type].end(); ++iter) {
205 bool isEquals = false;
206 napi_strict_equals(env, jsListenerObject, iter->first->GetNapiValue(), &isEquals);
207 if (isEquals) {
208 WLOGFE("[NAPI]Method %{public}s has already been registered", type.c_str());
209 return true;
210 }
211 }
212 return false;
213 }
214
215 } // namespace Rosen
216 } // namespace OHOS
217