1 /*
2 * Copyright (c) 2025 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 <hitrace_meter.h>
16 #include <algorithm>
17
18 #include "ani.h"
19 #include "singleton_container.h"
20 #include "window_manager_hilog.h"
21 #include "dm_common.h"
22 #include "refbase.h"
23 #include "screen_ani_manager.h"
24 #include "screen_ani_utils.h"
25 #include "screen_ani_listener.h"
26 #include "ani_err_utils.h"
27
28 namespace OHOS {
29 namespace Rosen {
30
ScreenManagerAni()31 ScreenManagerAni::ScreenManagerAni()
32 {
33 }
34
registerCallback(ani_env * env,ani_string type,ani_ref callback,ani_long nativeObj)35 void ScreenManagerAni::registerCallback(ani_env* env, ani_string type, ani_ref callback, ani_long nativeObj)
36 {
37 TLOGI(WmsLogTag::DMS, "[ANI] start to register screen callback: %{public}" PRId64, nativeObj);
38 ScreenManagerAni* screenManagerAni = reinterpret_cast<ScreenManagerAni*>(nativeObj);
39 if (screenManagerAni != nullptr) {
40 screenManagerAni->onRegisterCallback(env, type, callback);
41 } else {
42 TLOGE(WmsLogTag::DMS, "[ANI] screenManagerAni null ptr");
43 }
44 }
45
unRegisterCallback(ani_env * env,ani_string type,ani_long nativeObj,ani_ref callback)46 void ScreenManagerAni::unRegisterCallback(ani_env* env, ani_string type, ani_long nativeObj, ani_ref callback)
47 {
48 TLOGI(WmsLogTag::DMS, "[ANI] unRegisterCallback begin");
49 ScreenManagerAni* screenManagerAni = reinterpret_cast<ScreenManagerAni*>(nativeObj);
50 if (screenManagerAni != nullptr) {
51 screenManagerAni->onUnRegisterCallback(env, type, callback);
52 } else {
53 TLOGI(WmsLogTag::DMS, "[ANI] null ptr");
54 }
55 }
56
onRegisterCallback(ani_env * env,ani_string type,ani_ref callback)57 void ScreenManagerAni::onRegisterCallback(ani_env* env, ani_string type, ani_ref callback)
58 {
59 ani_ref cbRef{};
60 std::string typeString;
61 ScreenAniUtils::GetStdString(env, type, typeString);
62 if (env->GlobalReference_Create(callback, &cbRef) != ANI_OK) {
63 TLOGE(WmsLogTag::DMS, "[ANI] create global ref fail");
64 }
65 if (IsCallbackRegistered(env, typeString, cbRef)) {
66 TLOGI(WmsLogTag::DMS, "[ANI] type %{public}s callback already registered!", typeString.c_str());
67 return;
68 }
69 TLOGI(WmsLogTag::DMS, "[ANI] begin");
70 std::lock_guard<std::mutex> lock(mtx_);
71 ani_boolean callbackUndefined = 0;
72 env->Reference_IsUndefined(cbRef, &callbackUndefined);
73 DmErrorCode ret;
74 if (callbackUndefined) {
75 std::string errMsg = "[ANI] failed to register screen listener with type, cbk null or undefined";
76 TLOGE(WmsLogTag::DMS, "callbackNull or undefined");
77 AniErrUtils::ThrowBusinessError(env, DmErrorCode::DM_ERROR_INVALID_PARAM, errMsg);
78 return;
79 }
80 TLOGI(WmsLogTag::DMS, "create listener");
81 sptr<ScreenAniListener> screenAniListener = new(std::nothrow) ScreenAniListener(env);
82 if (screenAniListener == nullptr) {
83 TLOGE(WmsLogTag::DMS, "[ANI] screenListener is nullptr");
84 AniErrUtils::ThrowBusinessError(env, DMError::DM_ERROR_INVALID_PARAM, "screenListener is nullptr");
85 return;
86 }
87 screenAniListener->AddCallback(typeString, cbRef);
88 screenAniListener->SetMainEventHandler();
89 ret = processRegisterCallback(env, typeString, screenAniListener);
90 if (ret != DmErrorCode::DM_OK) {
91 TLOGE(WmsLogTag::DMS, "[ANI] register screen listener with type, errcode: %{public}d", ret);
92 std::string errMsg = "Failed to register screen listener with type";
93 AniErrUtils::ThrowBusinessError(env, ret, errMsg);
94 return;
95 }
96 // add listener to map
97 jsCbMap_[typeString][cbRef] = screenAniListener;
98 }
99
IsCallbackRegistered(ani_env * env,const std::string & type,ani_ref callback)100 bool ScreenManagerAni::IsCallbackRegistered(ani_env* env, const std::string& type, ani_ref callback)
101 {
102 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
103 TLOGI(WmsLogTag::DMS, "method %{public}s not registered!", type.c_str());
104 return false;
105 }
106
107 for (const auto& iter : jsCbMap_[type]) {
108 ani_boolean isEquals = false;
109 env->Reference_StrictEquals(callback, iter.first, &isEquals);
110 if (isEquals) {
111 TLOGE(WmsLogTag::DMS, "callback already registered!");
112 return true;
113 }
114 }
115 return false;
116 }
117
processRegisterCallback(ani_env * env,std::string & typeStr,sptr<ScreenAniListener> screenAniListener)118 DmErrorCode ScreenManagerAni::processRegisterCallback(ani_env* env, std::string& typeStr,
119 sptr<ScreenAniListener> screenAniListener)
120 {
121 DmErrorCode ret = DmErrorCode::DM_ERROR_INVALID_PARAM;
122 if (typeStr == EVENT_CHANGE) {
123 TLOGI(WmsLogTag::DMS, "processRegisterCallback %{public}s", typeStr.c_str());
124 ret = DM_JS_TO_ERROR_CODE_MAP.at(
125 SingletonContainer::Get<ScreenManager>().RegisterScreenListener(screenAniListener));
126 }
127 return ret;
128 }
129
onUnRegisterCallback(ani_env * env,ani_string type,ani_ref callback)130 void ScreenManagerAni::onUnRegisterCallback(ani_env* env, ani_string type, ani_ref callback)
131 {
132 TLOGI(WmsLogTag::DMS, "[ANI] onUnRegisterCallback begin");
133 std::string typeString;
134 ScreenAniUtils::GetStdString(env, type, typeString);
135 std::lock_guard<std::mutex> lock(mtx_);
136 ani_boolean callbackNull = 0;
137 env->Reference_IsUndefined(callback, &callbackNull);
138 DmErrorCode ret;
139 if (callbackNull) {
140 TLOGI(WmsLogTag::DMS, "[ANI] onUnRegisterCallback for all");
141 ret = DM_JS_TO_ERROR_CODE_MAP.at(UnRegisterAllScreenListenerWithType(typeString));
142 } else {
143 TLOGI(WmsLogTag::DMS, "[ANI] onUnRegisterCallback with type");
144 ret = DM_JS_TO_ERROR_CODE_MAP.at(UnRegisterScreenListenerWithType(typeString, env, callback));
145 }
146
147 if (ret != DmErrorCode::DM_OK) {
148 DmErrorCode errCode = DmErrorCode::DM_ERROR_INVALID_PARAM;
149 if (ret == DmErrorCode::DM_ERROR_NOT_SYSTEM_APP) {
150 errCode = ret;
151 }
152 std::string errMsg = "[ANI] failed to unregister screen listener with type";
153 TLOGE(WmsLogTag::DMS, "[ANI] failed to unregister screen listener with type");
154 AniErrUtils::ThrowBusinessError(env, DMError::DM_ERROR_INVALID_PARAM, errMsg);
155 }
156 }
157
UnRegisterScreenListenerWithType(std::string type,ani_env * env,ani_ref callback)158 DMError ScreenManagerAni::UnRegisterScreenListenerWithType(std::string type, ani_env* env, ani_ref callback)
159 {
160 TLOGI(WmsLogTag::DMS, "[ANI] UnRegisterScreenListenerWithType begin");
161 DMError ret = DMError::DM_OK;
162 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
163 TLOGI(WmsLogTag::DMS, "[ANI] methodName %{public}s not registered!", type.c_str());
164 return ret;
165 }
166 ani_ref cbRef{};
167 if (env->GlobalReference_Create(callback, &cbRef) != ANI_OK) {
168 TLOGE(WmsLogTag::DMS, "[ANI]create global ref fail");
169 return DMError::DM_ERROR_INVALID_PARAM;
170 }
171 for (auto it = jsCbMap_[type].begin(); it != jsCbMap_[type].end();) {
172 ani_boolean isEquals = 0;
173 env->Reference_StrictEquals(cbRef, it->first, &isEquals);
174 if (isEquals) {
175 it->second->RemoveCallback(env, type, callback);
176 if (type == EVENT_CHANGE) {
177 TLOGI(WmsLogTag::DMS, "[ANI] start to unregis screen event listener! event = %{public}s",
178 type.c_str());
179 sptr<ScreenManager::IScreenListener> thisListener(it->second);
180 ret = SingletonContainer::Get<ScreenManager>().UnregisterScreenListener(thisListener);
181 }
182 jsCbMap_[type].erase(it);
183 break;
184 } else {
185 it++;
186 }
187 }
188 if (jsCbMap_[type].empty()) {
189 jsCbMap_.erase(type);
190 }
191 return ret;
192 }
193
UnRegisterAllScreenListenerWithType(std::string type)194 DMError ScreenManagerAni::UnRegisterAllScreenListenerWithType(std::string type)
195 {
196 TLOGI(WmsLogTag::DMS, "[ANI] UnregisterAllScreenListenerWithType begin");
197 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
198 TLOGI(WmsLogTag::DMS, "[ANI] UnregisterAllScreenListenerWithType methodName %{public}s not registered!",
199 type.c_str());
200 return DMError::DM_OK;
201 }
202 DMError ret = DMError::DM_OK;
203 for (auto it = jsCbMap_[type].begin(); it != jsCbMap_[type].end();) {
204 it->second->RemoveAllCallback();
205 if (type == EVENT_CHANGE) {
206 sptr<ScreenManager::IScreenListener> thisListener(it->second);
207 ret = SingletonContainer::Get<ScreenManager>().UnregisterScreenListener(thisListener);
208 }
209 jsCbMap_[type].erase(it++);
210 TLOGI(WmsLogTag::DMS, "[ANI] UnregisterAllScreenListenerWithType end");
211 }
212 jsCbMap_.erase(type);
213 return ret;
214 }
215
216
initScreenManagerAni(ani_namespace screenNameSpace,ani_env * env)217 ani_status ScreenManagerAni::initScreenManagerAni(ani_namespace screenNameSpace, ani_env* env)
218 {
219 TLOGI(WmsLogTag::DMS, "[ANI]");
220 ani_function setObjFunc = nullptr;
221 ani_status ret = env->Namespace_FindFunction(screenNameSpace, "setScreenMgrRef", "J:V", &setObjFunc);
222 if (ret != ANI_OK) {
223 TLOGE(WmsLogTag::DMS, "[ANI] find setNativeObj func fail %{public}u", ret);
224 return ret;
225 }
226 std::unique_ptr<ScreenManagerAni> aniScreenManager = std::make_unique<ScreenManagerAni>();
227 ret = env->Function_Call_Void(setObjFunc, aniScreenManager.release());
228 if (ret != ANI_OK) {
229 TLOGE(WmsLogTag::DMS, "[ANI] find setNativeObj func fail %{public}u", ret);
230 return ret;
231 }
232 return ret;
233 }
234
235 extern "C" {
ANI_Constructor(ani_vm * vm,uint32_t * result)236 ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
237 {
238 using namespace OHOS::Rosen;
239 TLOGI(WmsLogTag::DMS, "[ANI] start to ANI_Constructor");
240 ani_status ret;
241 ani_env *env;
242 if ((ret = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK) {
243 TLOGE(WmsLogTag::DMS, "[ANI] null env");
244 return ANI_NOT_FOUND;
245 }
246 ani_namespace nsp;
247 if ((ret = env->FindNamespace("L@ohos/screen/screen;", &nsp)) != ANI_OK) {
248 TLOGE(WmsLogTag::DMS, "[ANI] null env %{public}u", ret);
249 return ANI_NOT_FOUND;
250 }
251 ScreenManagerAni::initScreenManagerAni(nsp, env);
252 std::array funcs = {
253 ani_native_function {"syncOn", nullptr,
254 reinterpret_cast<void *>(ScreenManagerAni::registerCallback)},
255 ani_native_function {"syncOff", nullptr,
256 reinterpret_cast<void *>(ScreenManagerAni::unRegisterCallback)}
257 };
258 if ((ret = env->Namespace_BindNativeFunctions(nsp, funcs.data(), funcs.size()))) {
259 TLOGE(WmsLogTag::DMS, "[ANI] bind namespace fail %{public}u", ret);
260 return ANI_NOT_FOUND;
261 }
262 *result = ANI_VERSION_1;
263 return ANI_OK;
264 }
265 }
266
267 }
268 }