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 "display_ani_listener.h"
20 #include "display_ani.h"
21 #include "display_ani_manager.h"
22 #include "display_info.h"
23 #include "display.h"
24 #include "singleton_container.h"
25 #include "display_manager.h"
26 #include "window_manager_hilog.h"
27 #include "dm_common.h"
28 #include "display_ani_utils.h"
29 #include "refbase.h"
30 #include "ani_err_utils.h"
31
32 namespace OHOS {
33 namespace Rosen {
34
DisplayManagerAni()35 DisplayManagerAni::DisplayManagerAni()
36 {
37 }
38
initDisplayManagerAni(ani_namespace displayNameSpace,ani_env * env)39 ani_status DisplayManagerAni::initDisplayManagerAni(ani_namespace displayNameSpace, ani_env* env)
40 {
41 TLOGI(WmsLogTag::DMS, "[ANI]");
42 ani_function setObjFunc = nullptr;
43 ani_status ret = env->Namespace_FindFunction(displayNameSpace, "setDisplayMgrRef", "J:V", &setObjFunc);
44 if (ret != ANI_OK) {
45 TLOGE(WmsLogTag::DMS, "[ANI] find setNativeObj func fail %{public}u", ret);
46 return ret;
47 }
48 std::unique_ptr<DisplayManagerAni> aniDisplayManager = std::make_unique<DisplayManagerAni>();
49 ret = env->Function_Call_Void(setObjFunc, aniDisplayManager.release());
50 if (ret != ANI_OK) {
51 TLOGE(WmsLogTag::DMS, "[ANI] find setNativeObj func fail %{public}u", ret);
52 return ret;
53 }
54 return ret;
55 }
56
getFoldDisplayModeAni(ani_env * env)57 ani_int DisplayManagerAni::getFoldDisplayModeAni(ani_env* env)
58 {
59 auto mode = SingletonContainer::Get<DisplayManager>().GetFoldDisplayMode();
60 TLOGI(WmsLogTag::DMS, "[ANI]" PRIu64", getFoldDisplayMode = %{public}u", mode);
61 return static_cast<ani_int>(mode);
62 }
63
isFoldableAni(ani_env * env)64 ani_boolean DisplayManagerAni::isFoldableAni(ani_env* env)
65 {
66 bool foldable = SingletonContainer::Get<DisplayManager>().IsFoldable();
67 TLOGI(WmsLogTag::DMS, "[ANI]" PRIu64", isFoldable = %{public}u", foldable);
68 return static_cast<ani_boolean>(foldable);
69 }
70
getFoldStatus(ani_env * env)71 ani_int DisplayManagerAni::getFoldStatus(ani_env* env)
72 {
73 auto status = SingletonContainer::Get<DisplayManager>().GetFoldStatus();
74 TLOGI(WmsLogTag::DMS, "[ANI]" PRIu64", getFoldStatus = %{public}u", status);
75 return static_cast<ani_int>(status);
76 }
77
getCurrentFoldCreaseRegion(ani_env * env,ani_object obj,ani_long nativeObj)78 void DisplayManagerAni::getCurrentFoldCreaseRegion(ani_env* env, ani_object obj, ani_long nativeObj)
79 {
80 DisplayManagerAni* displayManagerAni = reinterpret_cast<DisplayManagerAni*>(nativeObj);
81 if (displayManagerAni != nullptr) {
82 displayManagerAni->onGetCurrentFoldCreaseRegion(env, obj);
83 } else {
84 TLOGI(WmsLogTag::DMS, "[ANI] null ptr");
85 }
86 }
87
onGetCurrentFoldCreaseRegion(ani_env * env,ani_object obj)88 void DisplayManagerAni::onGetCurrentFoldCreaseRegion(ani_env* env, ani_object obj)
89 {
90 TLOGI(WmsLogTag::DMS, "[ANI] getCurrentFoldCreaseRegion begin instance");
91 sptr<FoldCreaseRegion> region = SingletonContainer::Get<DisplayManager>().GetCurrentFoldCreaseRegion();
92 if (region == nullptr) {
93 return;
94 }
95 TLOGI(WmsLogTag::DMS, "[ANI] SingletonContainer getCurrentFoldCreaseRegion");
96 uint64_t displayId = region->GetDisplayId();
97 std::vector<DMRect> rects = region->GetCreaseRects();
98 if (rects.size() == 0) {
99 return;
100 }
101 TLOGI(WmsLogTag::DMS, "[ANI] DisplayManager getCurrentFoldCreaseRegion success %{public}d", (int)displayId);
102 if (ANI_OK != env->Object_SetFieldByName_Double(obj, "<property>displayId", (ani_double)displayId)) {
103 TLOGE(WmsLogTag::DMS, "[ANI] set displayId field fail");
104 }
105 ani_ref creaseRectsObj{};
106 if (ANI_OK != env->Object_GetFieldByName_Ref(obj, "<property>creaseRects", &creaseRectsObj)) {
107 TLOGE(WmsLogTag::DMS, "[ANI] get ani_array len fail");
108 }
109 ani_double length;
110 if (ANI_OK != env->Object_GetPropertyByName_Double(static_cast<ani_object>(creaseRectsObj), "length", &length)) {
111 TLOGE(WmsLogTag::DMS, "[ANI] get ani_array len fail");
112 }
113 TLOGI(WmsLogTag::DMS, "[ANI] set CurrentFoldCreaseRegion property begin");
114 for (size_t i = 0; i < std::min(int(length), static_cast<int>(rects.size())); i++) {
115 ani_ref currentCrease;
116 if (ANI_OK != env->Object_CallMethodByName_Ref(static_cast<ani_object>(creaseRectsObj),
117 "$_get", "I:Lstd/core/Object;", ¤tCrease, (ani_int)i)) {
118 TLOGE(WmsLogTag::DMS, "[ANI] get ani_array index %{public}u fail", (ani_int)i);
119 }
120 TLOGI(WmsLogTag::DMS, "current i: %{public}u", (ani_int)i);
121 DisplayAniUtils::convertRect(rects[i], static_cast<ani_object>(currentCrease), env);
122 }
123 }
124
getAllDisplaysAni(ani_env * env,ani_object arrayObj)125 void DisplayManagerAni::getAllDisplaysAni(ani_env* env, ani_object arrayObj)
126 {
127 TLOGI(WmsLogTag::DMS, "[ANI] getAllDisplaysAni start");
128 std::vector<sptr<Display>> displays = SingletonContainer::Get<DisplayManager>().GetAllDisplays();
129 if (displays.empty()) {
130 AniErrUtils::ThrowBusinessError(env, DmErrorCode::DM_ERROR_INVALID_SCREEN, "");
131 }
132 ani_double length;
133 if (ANI_OK != env->Object_GetPropertyByName_Double(arrayObj, "length", &length)) {
134 TLOGE(WmsLogTag::DMS, "[ANI] get ani_array len fail");
135 }
136
137 for (int i = 0; i < std::min(int(length), static_cast<int>(displays.size())); i++) {
138 ani_ref currentDisplay;
139 if (ANI_OK != env->Object_CallMethodByName_Ref(arrayObj, "$_get", "I:Lstd/core/Object;",
140 ¤tDisplay, (ani_int)i)) {
141 TLOGE(WmsLogTag::DMS, "[ANI] get ani_array index %{public}u fail", (ani_int)i);
142 }
143 TLOGI(WmsLogTag::DMS, "current i: %{public}d", i);
144 DisplayAniUtils::cvtDisplay(displays[i], env, static_cast<ani_object>(currentDisplay));
145 }
146 TLOGI(WmsLogTag::DMS, "[ANI] getAllDisplaysAni end");
147 }
148
getDisplayByIdSyncAni(ani_env * env,ani_object obj,ani_double displayId)149 void DisplayManagerAni::getDisplayByIdSyncAni(ani_env* env, ani_object obj, ani_double displayId)
150 {
151 TLOGE(WmsLogTag::DMS, "[ANI] getDisplayByIdSyncAni begin");
152 if (displayId < 0) {
153 TLOGE(WmsLogTag::DMS, "[ANI] Invalid displayId, less than 0");
154 return;
155 }
156 sptr<Display> display = SingletonContainer::Get<DisplayManager>().GetDisplayById(static_cast<DisplayId>(displayId));
157 if (display == nullptr) {
158 TLOGE(WmsLogTag::DMS, "[ANI] Display null");
159 AniErrUtils::ThrowBusinessError(env, DmErrorCode::DM_ERROR_SYSTEM_INNORMAL, "");
160 return;
161 }
162 DisplayAniUtils::cvtDisplay(display, env, obj);
163 }
164
getDefaultDisplaySyncAni(ani_env * env,ani_object obj)165 void DisplayManagerAni::getDefaultDisplaySyncAni(ani_env* env, ani_object obj)
166 {
167 sptr<Display> display = SingletonContainer::Get<DisplayManager>().GetDefaultDisplaySync(true);
168 if (display == nullptr) {
169 TLOGE(WmsLogTag::DMS, "[ANI] Display null");
170 return;
171 }
172 TLOGI(WmsLogTag::DMS, "[ANI] getDefaultDisplaySyncAni");
173 DisplayAniUtils::cvtDisplay(display, env, obj);
174 return;
175 }
176
registerCallback(ani_env * env,ani_string type,ani_ref callback,ani_long nativeObj)177 void DisplayManagerAni::registerCallback(ani_env* env, ani_string type,
178 ani_ref callback, ani_long nativeObj)
179 {
180 DisplayManagerAni* displayManagerAni = reinterpret_cast<DisplayManagerAni*>(nativeObj);
181 if (displayManagerAni != nullptr) {
182 displayManagerAni->onRegisterCallback(env, type, callback);
183 } else {
184 TLOGI(WmsLogTag::DMS, "[ANI] null ptr");
185 }
186 }
187
onRegisterCallback(ani_env * env,ani_string type,ani_ref callback)188 void DisplayManagerAni::onRegisterCallback(ani_env* env, ani_string type, ani_ref callback)
189 {
190 std::string typeString;
191 DisplayAniUtils::GetStdString(env, type, typeString);
192 ani_ref cbRef{};
193 if (env->GlobalReference_Create(callback, &cbRef) != ANI_OK) {
194 TLOGE(WmsLogTag::DMS, "[ANI] create global ref fail");
195 return;
196 }
197 if (IsCallbackRegistered(env, typeString, cbRef)) {
198 TLOGI(WmsLogTag::DMS, "[ANI] type %{public}s callback already registered!", typeString.c_str());
199 return;
200 }
201 TLOGI(WmsLogTag::DMS, "[ANI] onRegisterCallback");
202 std::lock_guard<std::mutex> lock(mtx_);
203 ani_boolean callbackUndefined = 0;
204 env->Reference_IsUndefined(cbRef, &callbackUndefined);
205 DmErrorCode ret;
206 if (callbackUndefined) {
207 std::string errMsg = "[ANI] failed to register display listener with type, cbk null or undefined";
208 TLOGE(WmsLogTag::DMS, "callbackNull or undefined");
209 AniErrUtils::ThrowBusinessError(env, DmErrorCode::DM_ERROR_INVALID_PARAM, errMsg);
210 return;
211 }
212 sptr<DisplayAniListener> displayAniListener = new(std::nothrow) DisplayAniListener(env);
213 if (displayAniListener == nullptr) {
214 TLOGE(WmsLogTag::DMS, "[ANI]displayListener is nullptr");
215 AniErrUtils::ThrowBusinessError(env, DMError::DM_ERROR_INVALID_PARAM, "displayListener is nullptr");
216 return;
217 }
218 displayAniListener->AddCallback(typeString, cbRef);
219 displayAniListener->SetMainEventHandler();
220
221 ret = processRegisterCallback(env, typeString, displayAniListener);
222 if (ret != DmErrorCode::DM_OK) {
223 TLOGE(WmsLogTag::DMS, "[ANI] register display listener with type, errcode: %{public}d", ret);
224 std::string errMsg = "Failed to register display listener with type";
225 AniErrUtils::ThrowBusinessError(env, DmErrorCode::DM_ERROR_INVALID_PARAM, errMsg);
226 return;
227 }
228 // add listener to map
229 jsCbMap_[typeString][cbRef] = displayAniListener;
230 }
231
IsCallbackRegistered(ani_env * env,const std::string & type,ani_ref callback)232 bool DisplayManagerAni::IsCallbackRegistered(ani_env* env, const std::string& type, ani_ref callback)
233 {
234 std::lock_guard<std::mutex> lock(mtx_);
235 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
236 TLOGI(WmsLogTag::DMS, "method %{public}s not registered!", type.c_str());
237 return false;
238 }
239
240 for (const auto& iter : jsCbMap_[type]) {
241 ani_boolean isEquals = false;
242 env->Reference_StrictEquals(callback, iter.first, &isEquals);
243 if (isEquals) {
244 TLOGE(WmsLogTag::DMS, "callback already registered!");
245 return true;
246 }
247 }
248 return false;
249 }
250
processRegisterCallback(ani_env * env,std::string & typeStr,sptr<DisplayAniListener> displayAniListener)251 DmErrorCode DisplayManagerAni::processRegisterCallback(ani_env* env, std::string& typeStr,
252 sptr<DisplayAniListener> displayAniListener)
253 {
254 DmErrorCode ret = DmErrorCode::DM_ERROR_INVALID_PARAM;
255 if (typeStr == EVENT_ADD || typeStr == EVENT_REMOVE || typeStr == EVENT_CHANGE) {
256 TLOGI(WmsLogTag::DMS, "processRegisterCallback %{public}s", typeStr.c_str());
257 ret = DM_JS_TO_ERROR_CODE_MAP.at(
258 SingletonContainer::Get<DisplayManager>().RegisterDisplayListener(displayAniListener));
259 } else if (typeStr == EVENT_FOLD_STATUS_CHANGED) {
260 ret = DM_JS_TO_ERROR_CODE_MAP.at(
261 SingletonContainer::Get<DisplayManager>().RegisterFoldStatusListener(displayAniListener));
262 } else if (typeStr == EVENT_DISPLAY_MODE_CHANGED) {
263 ret = DM_JS_TO_ERROR_CODE_MAP.at(
264 SingletonContainer::Get<DisplayManager>().RegisterDisplayModeListener(displayAniListener));
265 }
266 return ret;
267 }
268
unRegisterCallback(ani_env * env,ani_string type,ani_long nativeObj,ani_ref callback)269 void DisplayManagerAni::unRegisterCallback(ani_env* env, ani_string type,
270 ani_long nativeObj, ani_ref callback)
271 {
272 TLOGI(WmsLogTag::DMS, "[ANI] unRegisterCallback begin");
273 DisplayManagerAni* displayManagerAni = reinterpret_cast<DisplayManagerAni*>(nativeObj);
274 if (displayManagerAni != nullptr) {
275 displayManagerAni->onUnRegisterCallback(env, type, callback);
276 } else {
277 TLOGI(WmsLogTag::DMS, "[ANI] null ptr");
278 }
279 }
280
onUnRegisterCallback(ani_env * env,ani_string type,ani_ref callback)281 void DisplayManagerAni::onUnRegisterCallback(ani_env* env, ani_string type, ani_ref callback)
282 {
283 TLOGI(WmsLogTag::DMS, "[ANI] onUnRegisterCallback begin");
284 ani_ref cbRef{};
285 if (env->GlobalReference_Create(callback, &cbRef) != ANI_OK) {
286 TLOGE(WmsLogTag::DMS, "[ANI] create global ref fail");
287 return;
288 }
289 std::string typeString;
290 DisplayAniUtils::GetStdString(env, type, typeString);
291 std::lock_guard<std::mutex> lock(mtx_);
292 ani_boolean callbackNull = 0;
293 env->Reference_IsUndefined(cbRef, &callbackNull);
294 DmErrorCode ret;
295 if (callbackNull) {
296 TLOGI(WmsLogTag::DMS, "[ANI] onUnRegisterCallback for all");
297 ret = DM_JS_TO_ERROR_CODE_MAP.at(UnregisterAllDisplayListenerWithType(typeString));
298 } else {
299 TLOGI(WmsLogTag::DMS, "[ANI] onUnRegisterCallback with type");
300 ret = DM_JS_TO_ERROR_CODE_MAP.at(UnRegisterDisplayListenerWithType(typeString, env, cbRef));
301 }
302
303 if (ret != DmErrorCode::DM_OK) {
304 DmErrorCode errCode = DmErrorCode::DM_ERROR_INVALID_PARAM;
305 if (ret == DmErrorCode::DM_ERROR_NOT_SYSTEM_APP) {
306 errCode = ret;
307 }
308 std::string errMsg = "[ANI] failed to unregister display listener with type";
309 TLOGE(WmsLogTag::DMS, "[ANI] failed to unregister display listener with type");
310 AniErrUtils::ThrowBusinessError(env, DMError::DM_ERROR_INVALID_PARAM, errMsg);
311 }
312 }
313
UnRegisterDisplayListenerWithType(std::string type,ani_env * env,ani_ref callback)314 DMError DisplayManagerAni::UnRegisterDisplayListenerWithType(std::string type, ani_env* env, ani_ref callback)
315 {
316 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
317 TLOGI(WmsLogTag::DMS, "[ANI] methodName %{public}s not registered!", type.c_str());
318 return DMError::DM_OK;
319 }
320 DMError ret = DMError::DM_OK;
321 for (auto it = jsCbMap_[type].begin(); it != jsCbMap_[type].end(); it++) {
322 bool isEquals = it->second->IsAniCallBackExist(env, type, callback);
323 TLOGI(WmsLogTag::DMS, "[ANI] isEquals %{public}u", isEquals);
324 if (isEquals) {
325 TLOGI(WmsLogTag::DMS, "[ANI] isEquals check begin");
326 it->second->RemoveCallback(env, type, callback);
327 if (type == EVENT_ADD || type == EVENT_REMOVE || type == EVENT_CHANGE) {
328 TLOGI(WmsLogTag::DMS, "[ANI] start to unregis display event listener! event = %{public}s",
329 type.c_str());
330 sptr<DisplayManager::IDisplayListener> thisListener(it->second);
331 ret = SingletonContainer::Get<DisplayManager>().UnregisterDisplayListener(thisListener);
332 } else if (type == EVENT_FOLD_STATUS_CHANGED) {
333 TLOGI(WmsLogTag::DMS, "[ANI] start to unregis FoldStatusListener event listener! event = %{public}s",
334 type.c_str());
335 sptr<DisplayManager::IFoldStatusListener> thisListener(it->second);
336 ret = SingletonContainer::Get<DisplayManager>().UnregisterFoldStatusListener(thisListener);
337 TLOGI(WmsLogTag::DMS, "[ANI] UnRegisterDisplayListener foldStatusChange success");
338 } else if (type == EVENT_DISPLAY_MODE_CHANGED) {
339 TLOGI(WmsLogTag::DMS, "[ANI] start to unregis foldDisplayModeChange event listener! event = %{public}s",
340 type.c_str());
341 sptr<DisplayManager::IDisplayModeListener> thisListener(it->second);
342 ret = SingletonContainer::Get<DisplayManager>().UnregisterDisplayModeListener(thisListener);
343 TLOGI(WmsLogTag::DMS, "[ANI] UnRegisterDisplayListener foldDisplayModeChange success");
344 }
345 jsCbMap_[type].erase(it);
346 break;
347 }
348 }
349 return ret;
350 }
351
UnregisterAllDisplayListenerWithType(std::string type)352 DMError DisplayManagerAni::UnregisterAllDisplayListenerWithType(std::string type)
353 {
354 TLOGI(WmsLogTag::DMS, "[ANI] UnregisterAllDisplayListenerWithType begin");
355 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
356 TLOGI(WmsLogTag::DMS, "[ANI] UnregisterAllDisplayListenerWithType methodName %{public}s not registered!",
357 type.c_str());
358 return DMError::DM_OK;
359 }
360 DMError ret = DMError::DM_OK;
361 for (auto it = jsCbMap_[type].begin(); it != jsCbMap_[type].end();) {
362 it->second->RemoveAllCallback();
363 if (type == EVENT_ADD || type == EVENT_REMOVE || type == EVENT_CHANGE) {
364 sptr<DisplayManager::IDisplayListener> thisListener(it->second);
365 ret = SingletonContainer::Get<DisplayManager>().UnregisterDisplayListener(thisListener);
366 } else if (type == EVENT_FOLD_STATUS_CHANGED) {
367 sptr<DisplayManager::IFoldStatusListener> thisListener(it->second);
368 ret = SingletonContainer::Get<DisplayManager>().UnregisterFoldStatusListener(thisListener);
369 } else if (type == EVENT_DISPLAY_MODE_CHANGED) {
370 sptr<DisplayManager::IDisplayModeListener> thisListener(it->second);
371 ret = SingletonContainer::Get<DisplayManager>().UnregisterDisplayModeListener(thisListener);
372 }
373 jsCbMap_[type].erase(it++);
374 TLOGI(WmsLogTag::DMS, "[ANI] UnregisterAllDisplayListenerWithType end");
375 }
376 jsCbMap_.erase(type);
377 return ret;
378 }
379 }
380 }