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