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