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 18namespace OHOS { 19namespace Rosen { 20namespace { 21constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "JsRegisterManager"}; 22 23const 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 28const std::map<CaseType, std::map<std::string, ListenerFunctionType>> ListenerFunctionMap { 29 {CaseType::CASE_WINDOW, WindowListenerFunctionMap}, 30}; 31} 32 33JsWindowRegisterManager::JsWindowRegisterManager() 34{ 35} 36 37JsWindowRegisterManager::~JsWindowRegisterManager() 38{ 39} 40 41WmErrorCode 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 63WmErrorCode 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 80WmErrorCode 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 119WmErrorCode 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 136WmErrorCode 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 197bool 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