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