• 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 
16 #include <ani.h>
17 #include <string>
18 #include <unistd.h>
19 
20 #include "base/log/log.h"
21 #include "base/memory/ace_type.h"
22 #include "core/components_ng/base/observer_handler.h"
23 #include "core/pipeline_ng/pipeline_context.h"
24 
25 namespace {
26 // constexpr const char DENSITY_CHNAGE[] = "densityUpdate";
27 const char ANI_OBSERVER_NS[] = "L@ohos/arkui/observer/uiObserver;";
28 const char ANI_OBSERVER_CLS[] = "L@ohos/arkui/observer/uiObserver/UIObserverImpl;";
29 } // namespace
30 namespace OHOS::Ace {
31 class UiObserver {
32 public:
UiObserver(int32_t instanceId)33     explicit UiObserver(int32_t instanceId) : id_(instanceId) {}
34 
CallJsFunction(ani_env * env,std::list<ani_ref> & cbList)35     void CallJsFunction(ani_env* env, std::list<ani_ref>& cbList)
36     {
37         std::vector<ani_ref> vec;
38         ani_ref fnReturnVal;
39         for (auto& cb : cbList) {
40             env->FunctionalObject_Call(reinterpret_cast<ani_fn_object>(cb), vec.size(), vec.data(), &fnReturnVal);
41         }
42     }
43 
44     // UIObserver.on(type: "densityUpdate", uiContext | null, callback)
45     // register a listener on current page
RegisterDensityCallback(int32_t uiContextInstanceId,ani_ref & cb)46     void RegisterDensityCallback(int32_t uiContextInstanceId, ani_ref& cb)
47     {
48         id_ = uiContextInstanceId;
49         if (uiContextInstanceId == 0) {
50             uiContextInstanceId = Container::CurrentId();
51         }
52         auto iter = densityCbMap_.find(uiContextInstanceId);
53         if (iter == densityCbMap_.end()) {
54             densityCbMap_.emplace(uiContextInstanceId, std::list<ani_ref>({ cb }));
55             return;
56         }
57         auto& holder = iter->second;
58         if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
59             return;
60         }
61         holder.emplace_back(cb);
62     }
63     // UIObserver.off(type: "densityUpdate", uiContext | null, callback)
UnRegisterDensityCallback(ani_env * env,int32_t uiContextInstanceId,ani_ref & cb)64     void UnRegisterDensityCallback(ani_env* env, int32_t uiContextInstanceId, ani_ref& cb)
65     {
66         if (uiContextInstanceId == 0) {
67             uiContextInstanceId = Container::CurrentId();
68         }
69         auto iter = densityCbMap_.find(uiContextInstanceId);
70         if (iter == densityCbMap_.end()) {
71             return;
72         }
73         auto& holder = iter->second;
74         if (cb == nullptr) {
75             holder.clear();
76             return;
77         }
78         holder.erase(std::remove_if(
79                          holder.begin(), holder.end(), [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
80             holder.end());
81     }
82 
HandleDensityChange(ani_env * env,double density)83     void HandleDensityChange(ani_env* env, double density)
84     {
85         auto currentId = Container::CurrentId();
86         auto iter = densityCbMap_.find(currentId);
87         if (iter == densityCbMap_.end()) {
88             return;
89         }
90         auto& holder = iter->second;
91         std::vector<ani_ref> callbackParams;
92         ani_ref fnReturnVal;
93         ani_object res;
94         CreateDensityInfo(env, density, res);
95         callbackParams.emplace_back(res);
96         for (auto& cb : holder) {
97             env->FunctionalObject_Call(reinterpret_cast<ani_fn_object>(cb),
98                                        callbackParams.size(),
99                                        callbackParams.data(),
100                                        &fnReturnVal);
101         }
102     }
103 
AniEqual(ani_env * env,ani_ref cb,ani_ref cb1)104     ani_boolean AniEqual(ani_env* env, ani_ref cb, ani_ref cb1)
105     {
106         ani_boolean isEquals = false;
107         env->Reference_StrictEquals(cb, cb1, &isEquals);
108         return isEquals;
109     }
110 
CreateDensityInfo(ani_env * env,double density,ani_object & obj)111     void CreateDensityInfo(ani_env* env, double density, ani_object& obj)
112     {
113         static const char* className = "L@ohos/arkui/observer/uiObserver/DensityInfo;";
114         ani_class cls;
115         env->FindClass(className, &cls);
116         ani_method ctor;
117         env->Class_FindMethod(cls, "<ctor>", ":V", &ctor);
118         env->Object_New(cls, ctor, &obj);
119         env->Object_SetPropertyByName_Double(obj, "density", ani_double(density));
120     }
121 
122 private:
123     int32_t id_;
124     std::unordered_map<int32_t, std::list<ani_ref>> densityCbMap_;
125 };
126 
Unwrapp(ani_env * env,ani_object object)127 static UiObserver* Unwrapp(ani_env* env, ani_object object)
128 {
129     ani_long nativeAddr;
130     if (ANI_OK != env->Object_GetFieldByName_Long(object, "nativeObserverAddr", &nativeAddr)) {
131         return nullptr;
132     }
133     return reinterpret_cast<UiObserver*>(nativeAddr);
134 }
135 
ANIUtils_ANIStringToStdString(ani_env * env,ani_string ani_str)136 std::string ANIUtils_ANIStringToStdString(ani_env* env, ani_string ani_str)
137 {
138     ani_size strSize;
139     env->String_GetUTF8Size(ani_str, &strSize);
140 
141     std::vector<char> buffer(strSize + 1);
142     char* utf8Buffer = buffer.data();
143 
144     ani_size bytes_written = 0;
145     env->String_GetUTF8(ani_str, utf8Buffer, strSize + 1, &bytes_written);
146 
147     utf8Buffer[bytes_written] = '\0';
148     std::string content = std::string(utf8Buffer);
149     return content;
150 }
151 
On(ani_env * env,ani_object object,ani_string type,ani_fn_object fnObj)152 static void On([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_string type, ani_fn_object fnObj)
153 {
154     if (fnObj == nullptr) {
155         LOGE("observer-ani callback is undefined.");
156         return;
157     }
158     std::string typeStr = ANIUtils_ANIStringToStdString(env, type);
159     auto* observer = Unwrapp(env, object);
160     if (observer == nullptr) {
161         LOGE("observer-ani context is null.");
162         return;
163     }
164     ani_ref fnObjGlobalRef = nullptr;
165     env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
166     observer->RegisterDensityCallback(100000, fnObjGlobalRef);
167 }
168 
Off(ani_env * env,ani_object object,ani_string type,ani_fn_object fnObj)169 static void Off([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_string type, ani_fn_object fnObj)
170 {
171     LOGE("lzr in off");
172     auto* observer = Unwrapp(env, object);
173     if (observer == nullptr) {
174         LOGE("observer-ani context is null.");
175         return;
176     }
177     ani_ref fnObjGlobalRef = nullptr;
178     env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
179     observer->UnRegisterDensityCallback(env, 100000, fnObjGlobalRef);
180 }
181 
CreateObserver(ani_env * env,ani_int id)182 static ani_object CreateObserver([[maybe_unused]] ani_env* env, ani_int id)
183 {
184     ani_class cls;
185     if (ANI_OK != env->FindClass(ANI_OBSERVER_CLS, &cls)) {
186         LOGE("observer-ani not found class");
187         return nullptr;
188     }
189 
190     ani_method ctor;
191     if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
192         LOGE("observer-ani can not get construct method.");
193         return nullptr;
194     }
195 
196     auto* observer = new UiObserver(id);
197     auto densityChangeCallback = [observer, env](NG::AbilityContextInfo& info, double density) {
198         observer->HandleDensityChange(env, density);
199     };
200     NG::UIObserverHandler::GetInstance().SetHandleDensityChangeFuncForAni(densityChangeCallback);
201     ani_object context_object;
202     if (ANI_OK != env->Object_New(cls, ctor, &context_object, reinterpret_cast<ani_long>(observer))) {
203         LOGE("observer-ani Can not new object.");
204         delete observer;
205         return nullptr;
206     }
207     return context_object;
208 }
209 } // namespace OHOS::Ace
ANI_ConstructorForAni(ani_env * env)210 bool ANI_ConstructorForAni(ani_env* env)
211 {
212     ani_namespace ns;
213     if (ANI_OK != env->FindNamespace(ANI_OBSERVER_NS, &ns)) {
214         LOGE("observer-ani Not found ns");
215         return false;
216     }
217     std::array methods = {
218         ani_native_function { "createUIObserver", nullptr, reinterpret_cast<void*>(OHOS::Ace::CreateObserver) },
219     };
220 
221     if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size())) {
222         LOGE("observer-ani Namespace_BindNativeFunctions error");
223         return false;
224     }
225 
226     ani_class clsObserver;
227     if (ANI_OK != env->FindClass(ANI_OBSERVER_CLS, &clsObserver)) {
228         LOGE("observer-ani not found class");
229         return false;
230     }
231 
232     std::array methodsObserver = {
233         ani_native_function { "on", nullptr, reinterpret_cast<void*>(OHOS::Ace::On) },
234         ani_native_function { "off", nullptr, reinterpret_cast<void*>(OHOS::Ace::Off) },
235     };
236     if (ANI_OK != env->Class_BindNativeMethods(clsObserver, methodsObserver.data(), methodsObserver.size())) {
237         return false;
238     }
239     return true;
240 }
241 
ANI_Constructor(ani_vm * vm,uint32_t * result)242 ANI_EXPORT ani_status ANI_Constructor(ani_vm* vm, uint32_t* result)
243 {
244     ani_env* env;
245     if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
246         LOGE("observer-ani Unsupported ANI_VERSION_1");
247         return ANI_ERROR;
248     }
249     if (ANI_ConstructorForAni(env)) {
250         *result = ANI_VERSION_1;
251         return ANI_OK;
252     }
253     return ANI_ERROR;
254 }
255