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