1 /*
2 * Copyright (C) 2022 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 "napi_accessibility_utils.h"
17 #include "napi_accessibility_config_observer.h"
18
19 #include <uv.h>
20
21 #include "hilog_wrapper.h"
22 #include "napi/native_api.h"
23 #include "napi/native_node_api.h"
24
25 using namespace OHOS;
26 using namespace OHOS::Accessibility;
27 using namespace OHOS::AccessibilityNapi;
28 using namespace OHOS::AccessibilityConfig;
29
OnConfigChanged(const ConfigValue & value)30 void NAccessibilityConfigObserver::OnConfigChanged(const ConfigValue &value)
31 {
32 HILOG_INFO("id = [%{public}d]", static_cast<int32_t>(configId_));
33 switch (configId_) {
34 case CONFIG_CAPTION_STATE:
35 NotifyStateChanged2JS(value.captionState);
36 break;
37 case CONFIG_CAPTION_STYLE:
38 NotifyPropertyChanged2JS(value.captionStyle);
39 break;
40 case CONFIG_SCREEN_MAGNIFICATION:
41 NotifyStateChanged2JS(value.screenMagnifier);
42 break;
43 case CONFIG_MOUSE_KEY:
44 NotifyStateChanged2JS(value.mouseKey);
45 break;
46 case CONFIG_SHORT_KEY:
47 NotifyStateChanged2JS(value.shortkey);
48 break;
49 case CONFIG_SHORT_KEY_TARGET:
50 NotifyStringChanged2JS(value.shortkey_target);
51 break;
52 case CONFIG_MOUSE_AUTOCLICK:
53 NotifyIntChanged2JS(value.mouseAutoClick);
54 break;
55 case CONFIG_DALTONIZATION_COLOR_FILTER:
56 NotifyStringChanged2JS(ConvertDaltonizationTypeToString(value.daltonizationColorFilter));
57 break;
58 case CONFIG_CONTENT_TIMEOUT:
59 NotifyIntChanged2JS(static_cast<int32_t>(value.contentTimeout));
60 break;
61 case CONFIG_BRIGHTNESS_DISCOUNT:
62 NotifyFloatChanged2JS(value.brightnessDiscount);
63 break;
64 case CONFIG_AUDIO_BALANCE:
65 NotifyFloatChanged2JS(value.audioBalance);
66 break;
67 case CONFIG_HIGH_CONTRAST_TEXT:
68 NotifyStateChanged2JS(value.highContrastText);
69 break;
70 case CONFIG_INVERT_COLOR:
71 NotifyStateChanged2JS(value.invertColor);
72 break;
73 case CONFIG_AUDIO_MONO:
74 NotifyStateChanged2JS(value.audioMono);
75 break;
76 case CONFIG_ANIMATION_OFF:
77 NotifyStateChanged2JS(value.animationOff);
78 break;
79 default:
80 break;
81 }
82 }
83
NotifyStateChanged2JS(bool enabled)84 void NAccessibilityConfigObserver::NotifyStateChanged2JS(bool enabled)
85 {
86 HILOG_INFO("id = [%{public}d] enabled = [%{public}s]", static_cast<int32_t>(configId_), enabled ? "true" : "false");
87
88 StateCallbackInfo *callbackInfo = new(std::nothrow) StateCallbackInfo();
89 if (!callbackInfo) {
90 HILOG_ERROR("Failed to create callbackInfo.");
91 return;
92 }
93 callbackInfo->state_ = enabled;
94 callbackInfo->env_ = env_;
95 callbackInfo->ref_ = handlerRef_;
96 uv_work_t *work = new(std::nothrow) uv_work_t;
97 if (!work) {
98 HILOG_ERROR("Failed to create work.");
99 delete callbackInfo;
100 callbackInfo = nullptr;
101 return;
102 }
103 work->data = static_cast<void*>(callbackInfo);
104
105 uv_loop_s *loop = nullptr;
106 napi_get_uv_event_loop(env_, &loop);
107 int ret = uv_queue_work(loop, work, [](uv_work_t *work) {},
108 [](uv_work_t *work, int status) {
109 StateCallbackInfo *callbackInfo = static_cast<StateCallbackInfo*>(work->data);
110 napi_value jsEvent;
111 napi_create_object(callbackInfo->env_, &jsEvent);
112 napi_get_boolean(callbackInfo->env_, callbackInfo->state_, &jsEvent);
113
114 napi_value handler = nullptr;
115 napi_value callResult = nullptr;
116 napi_get_reference_value(callbackInfo->env_, callbackInfo->ref_, &handler);
117 napi_value undefined = nullptr;
118 napi_get_undefined(callbackInfo->env_, &undefined);
119 napi_call_function(callbackInfo->env_, undefined, handler, 1, &jsEvent, &callResult);
120 int32_t result;
121 napi_get_value_int32(callbackInfo->env_, callResult, &result);
122 HILOG_INFO("NotifyStateChangedJS napi_call_function result[%{public}d]", result);
123 delete callbackInfo;
124 callbackInfo = nullptr;
125 delete work;
126 work = nullptr;
127 });
128 if (ret != 0) {
129 HILOG_ERROR("Failed to execute NotifyStateChanged2JS work queue");
130 delete callbackInfo;
131 callbackInfo = nullptr;
132 delete work;
133 work = nullptr;
134 }
135 }
136
NotifyPropertyChanged2JS(const OHOS::AccessibilityConfig::CaptionProperty & caption)137 void NAccessibilityConfigObserver::NotifyPropertyChanged2JS(const OHOS::AccessibilityConfig::CaptionProperty &caption)
138 {
139 HILOG_INFO("id = [%{public}d]", static_cast<int32_t>(configId_));
140
141 CaptionCallbackInfo *callbackInfo = new(std::nothrow) CaptionCallbackInfo();
142 if (!callbackInfo) {
143 HILOG_ERROR("Failed to create callbackInfo.");
144 return;
145 }
146 callbackInfo->caption_ = caption;
147 callbackInfo->env_ = env_;
148 callbackInfo->ref_ = handlerRef_;
149 uv_work_t *work = new(std::nothrow) uv_work_t;
150 if (!work) {
151 HILOG_ERROR("Failed to create work.");
152 delete callbackInfo;
153 callbackInfo = nullptr;
154 return;
155 }
156 work->data = static_cast<void*>(callbackInfo);
157
158 uv_loop_s *loop = nullptr;
159 napi_get_uv_event_loop(env_, &loop);
160 int ret = uv_queue_work(loop, work, [](uv_work_t *work) {},
161 [](uv_work_t *work, int status) {
162 CaptionCallbackInfo *callbackInfo = static_cast<CaptionCallbackInfo*>(work->data);
163 napi_value jsEvent;
164 napi_create_object(callbackInfo->env_, &jsEvent);
165 ConvertCaptionPropertyToJS(callbackInfo->env_, jsEvent, callbackInfo->caption_);
166
167 napi_value handler = nullptr;
168 napi_value callResult = nullptr;
169 napi_get_reference_value(callbackInfo->env_, callbackInfo->ref_, &handler);
170 napi_value undefined = nullptr;
171 napi_get_undefined(callbackInfo->env_, &undefined);
172 napi_call_function(callbackInfo->env_, undefined, handler, 1, &jsEvent, &callResult);
173 int32_t result;
174 napi_get_value_int32(callbackInfo->env_, callResult, &result);
175 HILOG_INFO("NotifyPropertyChangedJS napi_call_function result[%{public}d]", result);
176 delete callbackInfo;
177 callbackInfo = nullptr;
178 delete work;
179 work = nullptr;
180 });
181 if (ret != 0) {
182 HILOG_ERROR("Failed to execute NotifyPropertyChanged2JS work queue");
183 delete callbackInfo;
184 callbackInfo = nullptr;
185 delete work;
186 work = nullptr;
187 }
188 }
189
NotifyStringChanged2JS(const std::string & value)190 void NAccessibilityConfigObserver::NotifyStringChanged2JS(const std::string& value)
191 {
192 HILOG_INFO("value = [%{public}s]", value.c_str());
193
194 StateCallbackInfo *callbackInfo = new(std::nothrow) StateCallbackInfo();
195 if (!callbackInfo) {
196 HILOG_ERROR("Failed to create callbackInfo.");
197 return;
198 }
199 callbackInfo->stringValue_ = value;
200 callbackInfo->env_ = env_;
201 callbackInfo->ref_ = handlerRef_;
202 uv_work_t *work = new(std::nothrow) uv_work_t;
203 if (!work) {
204 HILOG_ERROR("Failed to create work.");
205 delete callbackInfo;
206 callbackInfo = nullptr;
207 return;
208 }
209 work->data = static_cast<void*>(callbackInfo);
210
211 uv_loop_s *loop = nullptr;
212 napi_get_uv_event_loop(env_, &loop);
213 int ret = uv_queue_work(loop, work, [](uv_work_t *work) {},
214 [](uv_work_t *work, int status) {
215 StateCallbackInfo *callbackInfo = static_cast<StateCallbackInfo*>(work->data);
216 napi_value jsEvent;
217 napi_create_string_utf8(callbackInfo->env_, callbackInfo->stringValue_.c_str(),
218 callbackInfo->stringValue_.length(), &jsEvent);
219 napi_value handler = nullptr;
220 napi_value callResult = nullptr;
221 napi_get_reference_value(callbackInfo->env_, callbackInfo->ref_, &handler);
222 napi_value undefined = nullptr;
223 napi_get_undefined(callbackInfo->env_, &undefined);
224 napi_call_function(callbackInfo->env_, undefined, handler, 1, &jsEvent, &callResult);
225 size_t result;
226 const uint32_t BUF_SIZE = 1024;
227 char buf[BUF_SIZE] = {0};
228 napi_get_value_string_utf8(callbackInfo->env_, callResult, buf, BUF_SIZE, &result);
229 HILOG_INFO("NotifyStringChanged2JSInner napi_call_function result[%{public}zu]", result);
230 delete callbackInfo;
231 callbackInfo = nullptr;
232 delete work;
233 work = nullptr;
234 });
235 if (ret != 0) {
236 HILOG_ERROR("Failed to execute NotifyStringChanged2JS work queue");
237 delete callbackInfo;
238 callbackInfo = nullptr;
239 delete work;
240 work = nullptr;
241 }
242 }
243
NotifyIntChanged2JS(int32_t value)244 void NAccessibilityConfigObserver::NotifyIntChanged2JS(int32_t value)
245 {
246 HILOG_INFO("id = [%{public}d] value = [%{public}d]", static_cast<int32_t>(configId_), value);
247
248 StateCallbackInfo *callbackInfo = new(std::nothrow) StateCallbackInfo();
249 if (!callbackInfo) {
250 HILOG_ERROR("Failed to create callbackInfo.");
251 return;
252 }
253 callbackInfo->int32Value_ = value;
254 callbackInfo->env_ = env_;
255 callbackInfo->ref_ = handlerRef_;
256 uv_work_t *work = new(std::nothrow) uv_work_t;
257 if (!work) {
258 HILOG_ERROR("Failed to create work.");
259 delete callbackInfo;
260 callbackInfo = nullptr;
261 return;
262 }
263 work->data = static_cast<void*>(callbackInfo);
264
265 uv_loop_s *loop = nullptr;
266 napi_get_uv_event_loop(env_, &loop);
267 int ret = uv_queue_work(
268 loop,
269 work,
270 [](uv_work_t *work) {},
271 [](uv_work_t *work, int status) {
272 StateCallbackInfo *callbackInfo = static_cast<StateCallbackInfo*>(work->data);
273 napi_value jsEvent;
274 napi_create_int32(callbackInfo->env_, callbackInfo->int32Value_, &jsEvent);
275
276 napi_value handler = nullptr;
277 napi_value callResult = nullptr;
278 napi_get_reference_value(callbackInfo->env_, callbackInfo->ref_, &handler);
279 napi_value undefined = nullptr;
280 napi_get_undefined(callbackInfo->env_, &undefined);
281 napi_call_function(callbackInfo->env_, undefined, handler, 1, &jsEvent, &callResult);
282 int32_t result;
283 napi_get_value_int32(callbackInfo->env_, callResult, &result);
284 HILOG_INFO("NotifyIntChanged2JSInner napi_call_function result[%{public}d]", result);
285 delete callbackInfo;
286 callbackInfo = nullptr;
287 delete work;
288 work = nullptr;
289 });
290 if (ret != 0) {
291 HILOG_ERROR("Failed to execute NotifyIntChanged2JS work queue");
292 delete callbackInfo;
293 callbackInfo = nullptr;
294 delete work;
295 work = nullptr;
296 }
297 }
298
NotifyUintChanged2JS(uint32_t value)299 void NAccessibilityConfigObserver::NotifyUintChanged2JS(uint32_t value)
300 {
301 HILOG_INFO("id = [%{public}d] value = [%{public}u]", static_cast<int32_t>(configId_), value);
302
303 StateCallbackInfo *callbackInfo = new(std::nothrow) StateCallbackInfo();
304 if (!callbackInfo) {
305 HILOG_ERROR("Failed to create callbackInfo.");
306 return;
307 }
308 callbackInfo->uint32Value_ = value;
309 callbackInfo->env_ = env_;
310 callbackInfo->ref_ = handlerRef_;
311 uv_work_t *work = new(std::nothrow) uv_work_t;
312 if (!work) {
313 HILOG_ERROR("Failed to create work.");
314 delete callbackInfo;
315 callbackInfo = nullptr;
316 return;
317 }
318 work->data = static_cast<void*>(callbackInfo);
319
320 uv_loop_s *loop = nullptr;
321 napi_get_uv_event_loop(env_, &loop);
322 int ret = uv_queue_work(
323 loop,
324 work,
325 [](uv_work_t *work) {},
326 [](uv_work_t *work, int status) {
327 StateCallbackInfo *callbackInfo = static_cast<StateCallbackInfo*>(work->data);
328 napi_value jsEvent;
329 napi_create_uint32(callbackInfo->env_, callbackInfo->uint32Value_, &jsEvent);
330
331 napi_value handler = nullptr;
332 napi_value callResult = nullptr;
333 napi_get_reference_value(callbackInfo->env_, callbackInfo->ref_, &handler);
334 napi_value undefined = nullptr;
335 napi_get_undefined(callbackInfo->env_, &undefined);
336 napi_call_function(callbackInfo->env_, undefined, handler, 1, &jsEvent, &callResult);
337 uint32_t result;
338 napi_get_value_uint32(callbackInfo->env_, callResult, &result);
339 HILOG_INFO("NotifyUintChanged2JSInner napi_call_function result[%{public}d]", result);
340 delete callbackInfo;
341 callbackInfo = nullptr;
342 delete work;
343 work = nullptr;
344 });
345 if (ret != 0) {
346 HILOG_ERROR("Failed to execute NotifyUintChanged2JS work queue");
347 delete callbackInfo;
348 callbackInfo = nullptr;
349 delete work;
350 work = nullptr;
351 }
352 }
353
NotifyFloatChanged2JS(float value)354 void NAccessibilityConfigObserver::NotifyFloatChanged2JS(float value)
355 {
356 HILOG_INFO("id = [%{public}d] value = [%{public}f]", static_cast<int32_t>(configId_), value);
357
358 StateCallbackInfo *callbackInfo = new(std::nothrow) StateCallbackInfo();
359 if (!callbackInfo) {
360 HILOG_ERROR("Failed to create callbackInfo.");
361 return;
362 }
363 callbackInfo->floatValue_ = value;
364 callbackInfo->env_ = env_;
365 callbackInfo->ref_ = handlerRef_;
366 uv_work_t *work = new(std::nothrow) uv_work_t;
367 if (!work) {
368 HILOG_ERROR("Failed to create work.");
369 delete callbackInfo;
370 callbackInfo = nullptr;
371 return;
372 }
373 work->data = static_cast<void*>(callbackInfo);
374
375 uv_loop_s *loop = nullptr;
376 napi_get_uv_event_loop(env_, &loop);
377 int ret = uv_queue_work(
378 loop,
379 work,
380 [](uv_work_t *work) {},
381 [](uv_work_t *work, int status) {
382 StateCallbackInfo *callbackInfo = static_cast<StateCallbackInfo*>(work->data);
383 napi_value jsEvent;
384 napi_create_double(callbackInfo->env_, double(callbackInfo->floatValue_), &jsEvent);
385
386 napi_value handler = nullptr;
387 napi_value callResult = nullptr;
388 napi_get_reference_value(callbackInfo->env_, callbackInfo->ref_, &handler);
389 napi_value undefined = nullptr;
390 napi_get_undefined(callbackInfo->env_, &undefined);
391 napi_call_function(callbackInfo->env_, undefined, handler, 1, &jsEvent, &callResult);
392 int32_t result;
393 napi_get_value_int32(callbackInfo->env_, callResult, &result);
394 HILOG_INFO("NotifyFloatChanged2JSInner napi_call_function result[%{public}d]", result);
395 delete callbackInfo;
396 callbackInfo = nullptr;
397 delete work;
398 work = nullptr;
399 });
400 if (ret != 0) {
401 HILOG_ERROR("Failed to execute NotifyFloatChanged2JS work queue");
402 delete callbackInfo;
403 callbackInfo = nullptr;
404 delete work;
405 work = nullptr;
406 }
407 }
408
SubscribeToFramework()409 void NAccessibilityConfigObserverImpl::SubscribeToFramework()
410 {
411 auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
412 for (int32_t index = 0; index < static_cast<int32_t>(CONFIG_ID_MAX); index ++) {
413 instance.SubscribeConfigObserver(static_cast<CONFIG_ID>(index), shared_from_this(), false);
414 }
415 }
416
OnConfigChanged(const OHOS::AccessibilityConfig::CONFIG_ID id,const OHOS::AccessibilityConfig::ConfigValue & value)417 void NAccessibilityConfigObserverImpl::OnConfigChanged(
418 const OHOS::AccessibilityConfig::CONFIG_ID id, const OHOS::AccessibilityConfig::ConfigValue& value)
419 {
420 HILOG_INFO();
421 std::lock_guard<std::mutex> lock(mutex_);
422 for (auto &observer : observers_) {
423 if (observer && observer->configId_ == id) {
424 observer->OnConfigChanged(value);
425 }
426 }
427 }
428
SubscribeObserver(napi_env env,OHOS::AccessibilityConfig::CONFIG_ID id,napi_value observer)429 void NAccessibilityConfigObserverImpl::SubscribeObserver(napi_env env,
430 OHOS::AccessibilityConfig::CONFIG_ID id, napi_value observer)
431 {
432 HILOG_INFO();
433 std::lock_guard<std::mutex> lock(mutex_);
434 for (auto iter = observers_.begin(); iter != observers_.end();) {
435 if (CheckObserverEqual(env, observer, (*iter)->env_, (*iter)->handlerRef_)) {
436 HILOG_DEBUG("Observer exist");
437 return;
438 } else {
439 iter++;
440 }
441 }
442
443 napi_ref handler = nullptr;
444 napi_create_reference(env, observer, 1, &handler);
445 std::shared_ptr<NAccessibilityConfigObserver> observerPtr =
446 std::make_shared<NAccessibilityConfigObserver>(env, handler, id);
447
448 observers_.emplace_back(observerPtr);
449 }
450
UnsubscribeObserver(napi_env env,OHOS::AccessibilityConfig::CONFIG_ID id,napi_value observer)451 void NAccessibilityConfigObserverImpl::UnsubscribeObserver(napi_env env,
452 OHOS::AccessibilityConfig::CONFIG_ID id, napi_value observer)
453 {
454 HILOG_INFO();
455 std::lock_guard<std::mutex> lock(mutex_);
456 for (auto iter = observers_.begin(); iter != observers_.end();) {
457 if ((*iter)->configId_ == id) {
458 if (CheckObserverEqual(env, observer, (*iter)->env_, (*iter)->handlerRef_)) {
459 observers_.erase(iter);
460 return;
461 } else {
462 iter++;
463 }
464 } else {
465 iter++;
466 }
467 }
468 }
469
UnsubscribeObservers(OHOS::AccessibilityConfig::CONFIG_ID id)470 void NAccessibilityConfigObserverImpl::UnsubscribeObservers(OHOS::AccessibilityConfig::CONFIG_ID id)
471 {
472 HILOG_INFO();
473 std::lock_guard<std::mutex> lock(mutex_);
474 for (auto iter = observers_.begin(); iter != observers_.end();) {
475 if ((*iter)->configId_ == id) {
476 iter = observers_.erase(iter);
477 } else {
478 iter++;
479 }
480 }
481 }