• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }