1 | import { Application } from '../application';
|
2 | import { Trace } from '../trace';
|
3 | import { SDK_VERSION } from '../utils/constants';
|
4 | import { resources } from '../utils/android';
|
5 | import { GestureTypes } from '../ui/gestures';
|
6 | import { notifyAccessibilityFocusState } from './accessibility-common';
|
7 | import { getAndroidAccessibilityManager } from './accessibility-service';
|
8 | import { AccessibilityRole, AccessibilityState, AndroidAccessibilityEvent } from './accessibility-types';
|
9 | export * from './accessibility-common';
|
10 | export * from './accessibility-types';
|
11 | export * from './font-scale';
|
12 | let clickableRolesMap = new Set();
|
13 | let lastFocusedView;
|
14 | function accessibilityEventHelper(view, eventType) {
|
15 | const eventName = accessibilityEventTypeMap.get(eventType);
|
16 | if (!isAccessibilityServiceEnabled()) {
|
17 | if (Trace.isEnabled()) {
|
18 | Trace.write(`accessibilityEventHelper: Service not active`, Trace.categories.Accessibility);
|
19 | }
|
20 | return;
|
21 | }
|
22 | if (!eventName) {
|
23 | Trace.write(`accessibilityEventHelper: unknown eventType: ${eventType}`, Trace.categories.Accessibility, Trace.messageType.error);
|
24 | return;
|
25 | }
|
26 | if (!view) {
|
27 | if (Trace.isEnabled()) {
|
28 | Trace.write(`accessibilityEventHelper: no owner: ${eventName}`, Trace.categories.Accessibility);
|
29 | }
|
30 | return;
|
31 | }
|
32 | const androidView = view.nativeViewProtected;
|
33 | if (!androidView) {
|
34 | if (Trace.isEnabled()) {
|
35 | Trace.write(`accessibilityEventHelper: no nativeView`, Trace.categories.Accessibility);
|
36 | }
|
37 | return;
|
38 | }
|
39 | switch (eventType) {
|
40 | case android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED: {
|
41 | |
42 |
|
43 |
|
44 |
|
45 | if (SDK_VERSION >= 26) {
|
46 |
|
47 | for (const tapGesture of view.getGestureObservers(GestureTypes.tap) ?? []) {
|
48 | tapGesture.callback({
|
49 | android: view.android,
|
50 | eventName: 'tap',
|
51 | ios: null,
|
52 | object: view,
|
53 | type: GestureTypes.tap,
|
54 | view: view,
|
55 | });
|
56 | }
|
57 | }
|
58 | return;
|
59 | }
|
60 | case android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
|
61 | const lastView = lastFocusedView?.get();
|
62 | if (lastView && view !== lastView) {
|
63 | const lastAndroidView = lastView.nativeViewProtected;
|
64 | if (lastAndroidView) {
|
65 | lastAndroidView.clearFocus();
|
66 | lastFocusedView = null;
|
67 | notifyAccessibilityFocusState(lastView, false, true);
|
68 | }
|
69 | }
|
70 | lastFocusedView = new WeakRef(view);
|
71 | notifyAccessibilityFocusState(view, true, false);
|
72 | return;
|
73 | }
|
74 | case android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
|
75 | const lastView = lastFocusedView?.get();
|
76 | if (lastView && view === lastView) {
|
77 | lastFocusedView = null;
|
78 | androidView.clearFocus();
|
79 | }
|
80 | notifyAccessibilityFocusState(view, false, true);
|
81 | return;
|
82 | }
|
83 | }
|
84 | }
|
85 | let TNSAccessibilityDelegate;
|
86 | const androidViewToTNSView = new WeakMap();
|
87 | let accessibilityEventMap;
|
88 | let accessibilityEventTypeMap;
|
89 | function ensureNativeClasses() {
|
90 | if (TNSAccessibilityDelegate) {
|
91 | return;
|
92 | }
|
93 |
|
94 | const AccessibilityDelegate = android.view.View['AccessibilityDelegate'];
|
95 | const RoleTypeMap = new Map([
|
96 | [AccessibilityRole.Button, android.widget.Button.class.getName()],
|
97 | [AccessibilityRole.Search, android.widget.EditText.class.getName()],
|
98 | [AccessibilityRole.Image, android.widget.ImageView.class.getName()],
|
99 | [AccessibilityRole.ImageButton, android.widget.ImageButton.class.getName()],
|
100 | [AccessibilityRole.KeyboardKey, android.inputmethodservice.Keyboard.Key.class.getName()],
|
101 | [AccessibilityRole.StaticText, android.widget.TextView.class.getName()],
|
102 | [AccessibilityRole.Adjustable, android.widget.SeekBar.class.getName()],
|
103 | [AccessibilityRole.Checkbox, android.widget.CheckBox.class.getName()],
|
104 | [AccessibilityRole.RadioButton, android.widget.RadioButton.class.getName()],
|
105 | [AccessibilityRole.SpinButton, android.widget.Spinner.class.getName()],
|
106 | [AccessibilityRole.Switch, android.widget.Switch.class.getName()],
|
107 | [AccessibilityRole.ProgressBar, android.widget.ProgressBar.class.getName()],
|
108 | ]);
|
109 | clickableRolesMap = new Set([AccessibilityRole.Button, AccessibilityRole.ImageButton]);
|
110 | const ignoreRoleTypesForTrace = new Set([AccessibilityRole.Header, AccessibilityRole.Link, AccessibilityRole.None, AccessibilityRole.Summary]);
|
111 | var TNSAccessibilityDelegateImpl = (function (_super) {
|
112 | __extends(TNSAccessibilityDelegateImpl, _super);
|
113 | function TNSAccessibilityDelegateImpl() {
|
114 | var _this = _super.call(this) || this;
|
115 | return global.__native(_this);
|
116 | }
|
117 | TNSAccessibilityDelegateImpl.prototype.getTnsView = function (androidView) {
|
118 | var _a;
|
119 | var view = (_a = androidViewToTNSView.get(androidView)) === null || _a === void 0 ? void 0 : _a.get();
|
120 | if (!view) {
|
121 | androidViewToTNSView.delete(androidView);
|
122 | return null;
|
123 | }
|
124 | return view;
|
125 | };
|
126 | TNSAccessibilityDelegateImpl.prototype.onInitializeAccessibilityNodeInfo = function (host, info) {
|
127 | _super.prototype.onInitializeAccessibilityNodeInfo.call(this, host, info);
|
128 | var view = this.getTnsView(host);
|
129 | if (!view) {
|
130 | if (Trace.isEnabled()) {
|
131 | Trace.write("onInitializeAccessibilityNodeInfo ".concat(host, " ").concat(info, " no tns-view"), Trace.categories.Accessibility);
|
132 | }
|
133 | return;
|
134 | }
|
135 |
|
136 | var id = host.getTag(resources.getId(":id/nativescript_accessibility_id"));
|
137 | if (id != null) {
|
138 | info.setViewIdResourceName(id);
|
139 | }
|
140 | var accessibilityRole = view.accessibilityRole;
|
141 | if (accessibilityRole) {
|
142 | var androidClassName = RoleTypeMap.get(accessibilityRole);
|
143 | if (androidClassName) {
|
144 | var oldClassName = info.getClassName() || (SDK_VERSION >= 28 && host.getAccessibilityClassName()) || null;
|
145 | info.setClassName(androidClassName);
|
146 | if (Trace.isEnabled()) {
|
147 | Trace.write("".concat(view, ".accessibilityRole = \"").concat(accessibilityRole, "\" is mapped to \"").concat(androidClassName, "\" (was ").concat(oldClassName, "). ").concat(info.getClassName()), Trace.categories.Accessibility);
|
148 | }
|
149 | }
|
150 | else if (!ignoreRoleTypesForTrace.has(accessibilityRole)) {
|
151 | if (Trace.isEnabled()) {
|
152 | Trace.write("".concat(view, ".accessibilityRole = \"").concat(accessibilityRole, "\" is unknown"), Trace.categories.Accessibility);
|
153 | }
|
154 | }
|
155 | if (clickableRolesMap.has(accessibilityRole)) {
|
156 | if (Trace.isEnabled()) {
|
157 | Trace.write("onInitializeAccessibilityNodeInfo ".concat(view, " - set clickable role=").concat(accessibilityRole), Trace.categories.Accessibility);
|
158 | }
|
159 | info.setClickable(true);
|
160 | }
|
161 | if (SDK_VERSION >= 28) {
|
162 | if (accessibilityRole === AccessibilityRole.Header) {
|
163 | if (Trace.isEnabled()) {
|
164 | Trace.write("onInitializeAccessibilityNodeInfo ".concat(view, " - set heading role=").concat(accessibilityRole), Trace.categories.Accessibility);
|
165 | }
|
166 | info.setHeading(true);
|
167 | }
|
168 | else if (host.isAccessibilityHeading()) {
|
169 | if (Trace.isEnabled()) {
|
170 | Trace.write("onInitializeAccessibilityNodeInfo ".concat(view, " - set heading from host"), Trace.categories.Accessibility);
|
171 | }
|
172 | info.setHeading(true);
|
173 | }
|
174 | else {
|
175 | if (Trace.isEnabled()) {
|
176 | Trace.write("onInitializeAccessibilityNodeInfo ".concat(view, " - set not heading"), Trace.categories.Accessibility);
|
177 | }
|
178 | info.setHeading(false);
|
179 | }
|
180 | }
|
181 | switch (accessibilityRole) {
|
182 | case AccessibilityRole.Switch:
|
183 | case AccessibilityRole.RadioButton:
|
184 | case AccessibilityRole.Checkbox: {
|
185 | if (Trace.isEnabled()) {
|
186 | Trace.write("onInitializeAccessibilityNodeInfo ".concat(view, " - set checkable and check=").concat(view.accessibilityState === AccessibilityState.Checked), Trace.categories.Accessibility);
|
187 | }
|
188 | info.setCheckable(true);
|
189 | info.setChecked(view.accessibilityState === AccessibilityState.Checked);
|
190 | break;
|
191 | }
|
192 | default: {
|
193 | if (Trace.isEnabled()) {
|
194 | Trace.write("onInitializeAccessibilityNodeInfo ".concat(view, " - set enabled=").concat(view.accessibilityState !== AccessibilityState.Disabled, " and selected=").concat(view.accessibilityState === AccessibilityState.Selected), Trace.categories.Accessibility);
|
195 | }
|
196 | info.setEnabled(view.accessibilityState !== AccessibilityState.Disabled);
|
197 | info.setSelected(view.accessibilityState === AccessibilityState.Selected);
|
198 | break;
|
199 | }
|
200 | }
|
201 | }
|
202 | if (view.accessible) {
|
203 | info.setFocusable(true);
|
204 | }
|
205 | };
|
206 | TNSAccessibilityDelegateImpl.prototype.sendAccessibilityEvent = function (host, eventType) {
|
207 | _super.prototype.sendAccessibilityEvent.call(this, host, eventType);
|
208 | var view = this.getTnsView(host);
|
209 | if (!view) {
|
210 | console.log("skip - ".concat(host, " - ").concat(accessibilityEventTypeMap.get(eventType)));
|
211 | return;
|
212 | }
|
213 | try {
|
214 | accessibilityEventHelper(view, eventType);
|
215 | }
|
216 | catch (err) {
|
217 | console.error(err);
|
218 | }
|
219 | };
|
220 | return TNSAccessibilityDelegateImpl;
|
221 | }(AccessibilityDelegate));
|
222 | TNSAccessibilityDelegate = new TNSAccessibilityDelegateImpl();
|
223 | accessibilityEventMap = new Map([
|
224 | |
225 |
|
226 |
|
227 | [AndroidAccessibilityEvent.INVALID_POSITION, android.view.accessibility.AccessibilityEvent.INVALID_POSITION],
|
228 | |
229 |
|
230 |
|
231 | [AndroidAccessibilityEvent.MAX_TEXT_LENGTH, android.view.accessibility.AccessibilityEvent.MAX_TEXT_LENGTH],
|
232 | |
233 |
|
234 |
|
235 | [AndroidAccessibilityEvent.VIEW_CLICKED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED],
|
236 | |
237 |
|
238 |
|
239 | [AndroidAccessibilityEvent.VIEW_LONG_CLICKED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_LONG_CLICKED],
|
240 | |
241 |
|
242 |
|
243 | [AndroidAccessibilityEvent.VIEW_SELECTED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SELECTED],
|
244 | |
245 |
|
246 |
|
247 | [AndroidAccessibilityEvent.VIEW_FOCUSED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED],
|
248 | |
249 |
|
250 |
|
251 | [AndroidAccessibilityEvent.VIEW_TEXT_CHANGED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED],
|
252 | |
253 |
|
254 |
|
255 | [AndroidAccessibilityEvent.WINDOW_STATE_CHANGED, android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED],
|
256 | |
257 |
|
258 |
|
259 | [AndroidAccessibilityEvent.NOTIFICATION_STATE_CHANGED, android.view.accessibility.AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED],
|
260 | |
261 |
|
262 |
|
263 | [AndroidAccessibilityEvent.VIEW_HOVER_ENTER, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_HOVER_ENTER],
|
264 | |
265 |
|
266 |
|
267 | [AndroidAccessibilityEvent.VIEW_HOVER_EXIT, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_HOVER_EXIT],
|
268 | |
269 |
|
270 |
|
271 | [AndroidAccessibilityEvent.TOUCH_EXPLORATION_GESTURE_START, android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START],
|
272 | |
273 |
|
274 |
|
275 | [AndroidAccessibilityEvent.TOUCH_EXPLORATION_GESTURE_END, android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END],
|
276 | |
277 |
|
278 |
|
279 | [AndroidAccessibilityEvent.WINDOW_CONTENT_CHANGED, android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED],
|
280 | |
281 |
|
282 |
|
283 | [AndroidAccessibilityEvent.VIEW_SCROLLED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SCROLLED],
|
284 | |
285 |
|
286 |
|
287 | [AndroidAccessibilityEvent.VIEW_TEXT_SELECTION_CHANGED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED],
|
288 | |
289 |
|
290 |
|
291 | [AndroidAccessibilityEvent.ANNOUNCEMENT, android.view.accessibility.AccessibilityEvent.TYPE_ANNOUNCEMENT],
|
292 | |
293 |
|
294 |
|
295 | [AndroidAccessibilityEvent.VIEW_ACCESSIBILITY_FOCUSED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED],
|
296 | |
297 |
|
298 |
|
299 | [AndroidAccessibilityEvent.VIEW_ACCESSIBILITY_FOCUS_CLEARED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED],
|
300 | |
301 |
|
302 |
|
303 | [AndroidAccessibilityEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY],
|
304 | |
305 |
|
306 |
|
307 | [AndroidAccessibilityEvent.GESTURE_DETECTION_START, android.view.accessibility.AccessibilityEvent.TYPE_GESTURE_DETECTION_START],
|
308 | |
309 |
|
310 |
|
311 | [AndroidAccessibilityEvent.GESTURE_DETECTION_END, android.view.accessibility.AccessibilityEvent.TYPE_GESTURE_DETECTION_END],
|
312 | |
313 |
|
314 |
|
315 | [AndroidAccessibilityEvent.TOUCH_INTERACTION_START, android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_INTERACTION_START],
|
316 | |
317 |
|
318 |
|
319 | [AndroidAccessibilityEvent.TOUCH_INTERACTION_END, android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_INTERACTION_END],
|
320 | |
321 |
|
322 |
|
323 | [AndroidAccessibilityEvent.ALL_MASK, android.view.accessibility.AccessibilityEvent.TYPES_ALL_MASK],
|
324 | ]);
|
325 | accessibilityEventTypeMap = new Map([...accessibilityEventMap].map(([k, v]) => [v, k]));
|
326 | }
|
327 | let accessibilityStateChangeListener;
|
328 | let touchExplorationStateChangeListener;
|
329 | function updateAccessibilityServiceState() {
|
330 | const accessibilityManager = getAndroidAccessibilityManager();
|
331 | if (!accessibilityManager) {
|
332 | return;
|
333 | }
|
334 | accessibilityServiceEnabled = !!accessibilityManager.isEnabled() && !!accessibilityManager.isTouchExplorationEnabled();
|
335 | }
|
336 | let accessibilityServiceEnabled;
|
337 | export function isAccessibilityServiceEnabled() {
|
338 | if (typeof accessibilityServiceEnabled === 'boolean') {
|
339 | return accessibilityServiceEnabled;
|
340 | }
|
341 | const accessibilityManager = getAndroidAccessibilityManager();
|
342 | accessibilityStateChangeListener = new androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener({
|
343 | onAccessibilityStateChanged(enabled) {
|
344 | updateAccessibilityServiceState();
|
345 | if (Trace.isEnabled()) {
|
346 | Trace.write(`AccessibilityStateChangeListener state changed to: ${!!enabled}`, Trace.categories.Accessibility);
|
347 | }
|
348 | },
|
349 | });
|
350 | touchExplorationStateChangeListener = new androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener({
|
351 | onTouchExplorationStateChanged(enabled) {
|
352 | updateAccessibilityServiceState();
|
353 | if (Trace.isEnabled()) {
|
354 | Trace.write(`TouchExplorationStateChangeListener state changed to: ${!!enabled}`, Trace.categories.Accessibility);
|
355 | }
|
356 | },
|
357 | });
|
358 | androidx.core.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener(accessibilityManager, accessibilityStateChangeListener);
|
359 | androidx.core.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener(accessibilityManager, touchExplorationStateChangeListener);
|
360 | updateAccessibilityServiceState();
|
361 | Application.on(Application.exitEvent, (args) => {
|
362 | const activity = args.android;
|
363 | if (activity && !activity.isFinishing()) {
|
364 | return;
|
365 | }
|
366 | const accessibilityManager = getAndroidAccessibilityManager();
|
367 | if (accessibilityManager) {
|
368 | if (accessibilityStateChangeListener) {
|
369 | androidx.core.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener(accessibilityManager, accessibilityStateChangeListener);
|
370 | }
|
371 | if (touchExplorationStateChangeListener) {
|
372 | androidx.core.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener(accessibilityManager, touchExplorationStateChangeListener);
|
373 | }
|
374 | }
|
375 | accessibilityStateChangeListener = null;
|
376 | touchExplorationStateChangeListener = null;
|
377 | Application.off(Application.resumeEvent, updateAccessibilityServiceState);
|
378 | });
|
379 | Application.on(Application.resumeEvent, updateAccessibilityServiceState);
|
380 | return accessibilityServiceEnabled;
|
381 | }
|
382 | export function setupAccessibleView(view) {
|
383 | updateAccessibilityProperties(view);
|
384 | }
|
385 | let updateAccessibilityPropertiesMicroTask;
|
386 | let pendingViews = new Set();
|
387 | export function updateAccessibilityProperties(view) {
|
388 | if (!view.nativeViewProtected) {
|
389 | return;
|
390 | }
|
391 | pendingViews.add(view);
|
392 | if (updateAccessibilityPropertiesMicroTask)
|
393 | return;
|
394 | updateAccessibilityPropertiesMicroTask = true;
|
395 | Promise.resolve().then(() => {
|
396 | updateAccessibilityPropertiesMicroTask = false;
|
397 | let _pendingViews = Array.from(pendingViews);
|
398 | pendingViews = new Set();
|
399 | for (const view of _pendingViews) {
|
400 | if (!view.nativeViewProtected)
|
401 | continue;
|
402 | setAccessibilityDelegate(view);
|
403 | applyContentDescription(view);
|
404 | }
|
405 | _pendingViews = [];
|
406 | });
|
407 | }
|
408 | export function sendAccessibilityEvent(view, eventType, text) {
|
409 | if (!isAccessibilityServiceEnabled()) {
|
410 | return;
|
411 | }
|
412 | const cls = `sendAccessibilityEvent(${view}, ${eventType}, ${text})`;
|
413 | const androidView = view.nativeViewProtected;
|
414 | if (!androidView) {
|
415 | if (Trace.isEnabled()) {
|
416 | Trace.write(`${cls}: no nativeView`, Trace.categories.Accessibility);
|
417 | }
|
418 | return;
|
419 | }
|
420 | if (!eventType) {
|
421 | if (Trace.isEnabled()) {
|
422 | Trace.write(`${cls}: no eventName provided`, Trace.categories.Accessibility);
|
423 | }
|
424 | return;
|
425 | }
|
426 | if (!isAccessibilityServiceEnabled()) {
|
427 | if (Trace.isEnabled()) {
|
428 | Trace.write(`${cls} - TalkBack not enabled`, Trace.categories.Accessibility);
|
429 | }
|
430 | return;
|
431 | }
|
432 | const accessibilityManager = getAndroidAccessibilityManager();
|
433 | if (!accessibilityManager?.isEnabled()) {
|
434 | if (Trace.isEnabled()) {
|
435 | Trace.write(`${cls} - accessibility service not enabled`, Trace.categories.Accessibility);
|
436 | }
|
437 | return;
|
438 | }
|
439 | if (!accessibilityEventMap.has(eventType)) {
|
440 | if (Trace.isEnabled()) {
|
441 | Trace.write(`${cls} - unknown event`, Trace.categories.Accessibility);
|
442 | }
|
443 | return;
|
444 | }
|
445 | const eventInt = accessibilityEventMap.get(eventType);
|
446 | if (!text) {
|
447 | return androidView.sendAccessibilityEvent(eventInt);
|
448 | }
|
449 | const accessibilityEvent = android.view.accessibility.AccessibilityEvent.obtain(eventInt);
|
450 | accessibilityEvent.setSource(androidView);
|
451 | accessibilityEvent.getText().clear();
|
452 | if (!text) {
|
453 | applyContentDescription(view);
|
454 | text = androidView.getContentDescription() || view['title'];
|
455 | if (Trace.isEnabled()) {
|
456 | Trace.write(`${cls} - text not provided use androidView.getContentDescription() - ${text}`, Trace.categories.Accessibility);
|
457 | }
|
458 | }
|
459 | if (Trace.isEnabled()) {
|
460 | Trace.write(`${cls}: send event with text: '${JSON.stringify(text)}'`, Trace.categories.Accessibility);
|
461 | }
|
462 | if (text) {
|
463 | accessibilityEvent.getText().add(text);
|
464 | }
|
465 | accessibilityManager.sendAccessibilityEvent(accessibilityEvent);
|
466 | }
|
467 | export function updateContentDescription(view, forceUpdate) {
|
468 | if (!view.nativeViewProtected) {
|
469 | return;
|
470 | }
|
471 | return applyContentDescription(view, forceUpdate);
|
472 | }
|
473 | function setAccessibilityDelegate(view) {
|
474 | if (!view.nativeViewProtected) {
|
475 | return;
|
476 | }
|
477 | ensureNativeClasses();
|
478 | const androidView = view.nativeViewProtected;
|
479 | if (!androidView || !androidView.setAccessibilityDelegate) {
|
480 | return;
|
481 | }
|
482 | androidViewToTNSView.set(androidView, new WeakRef(view));
|
483 | let hasOldDelegate = false;
|
484 | if (typeof androidView.getAccessibilityDelegate === 'function') {
|
485 | hasOldDelegate = androidView.getAccessibilityDelegate() === TNSAccessibilityDelegate;
|
486 | }
|
487 | if (hasOldDelegate) {
|
488 | return;
|
489 | }
|
490 | androidView.setAccessibilityDelegate(TNSAccessibilityDelegate);
|
491 | }
|
492 | function applyContentDescription(view, forceUpdate) {
|
493 | let androidView = view.nativeViewProtected;
|
494 | if (!androidView || (androidView instanceof android.widget.TextView && !view._androidContentDescriptionUpdated)) {
|
495 | return null;
|
496 | }
|
497 | if (androidView instanceof androidx.appcompat.widget.Toolbar) {
|
498 | const numChildren = androidView.getChildCount();
|
499 | for (let i = 0; i < numChildren; i += 1) {
|
500 | const childAndroidView = androidView.getChildAt(i);
|
501 | if (childAndroidView instanceof androidx.appcompat.widget.AppCompatTextView) {
|
502 | androidView = childAndroidView;
|
503 | break;
|
504 | }
|
505 | }
|
506 | }
|
507 | const cls = `applyContentDescription(${view})`;
|
508 | const titleValue = view['title'];
|
509 | const textValue = view['text'];
|
510 | if (!forceUpdate && view._androidContentDescriptionUpdated === false && textValue === view['_lastText'] && titleValue === view['_lastTitle']) {
|
511 |
|
512 | return androidView.getContentDescription();
|
513 | }
|
514 | const contentDescriptionBuilder = new Array();
|
515 |
|
516 | if (view.accessibilityRole === AccessibilityRole.Switch) {
|
517 | const androidSwitch = new android.widget.Switch(Application.android.context);
|
518 | if (view.accessibilityState === AccessibilityState.Checked) {
|
519 | contentDescriptionBuilder.push(androidSwitch.getTextOn());
|
520 | }
|
521 | else {
|
522 | contentDescriptionBuilder.push(androidSwitch.getTextOff());
|
523 | }
|
524 | }
|
525 | if (view.accessibilityLabel) {
|
526 | if (Trace.isEnabled()) {
|
527 | Trace.write(`${cls} - have accessibilityLabel`, Trace.categories.Accessibility);
|
528 | }
|
529 | contentDescriptionBuilder.push(`${view.accessibilityLabel}`);
|
530 | }
|
531 | if (view.accessibilityValue) {
|
532 | if (Trace.isEnabled()) {
|
533 | Trace.write(`${cls} - have accessibilityValue`, Trace.categories.Accessibility);
|
534 | }
|
535 | contentDescriptionBuilder.push(`${view.accessibilityValue}`);
|
536 | }
|
537 | else if (textValue) {
|
538 | if (textValue !== view.accessibilityLabel) {
|
539 | if (Trace.isEnabled()) {
|
540 | Trace.write(`${cls} - don't have accessibilityValue - use 'text' value`, Trace.categories.Accessibility);
|
541 | }
|
542 | contentDescriptionBuilder.push(`${textValue}`);
|
543 | }
|
544 | }
|
545 | else if (titleValue) {
|
546 | if (titleValue !== view.accessibilityLabel) {
|
547 | if (Trace.isEnabled()) {
|
548 | Trace.write(`${cls} - don't have accessibilityValue - use 'title' value`, Trace.categories.Accessibility);
|
549 | }
|
550 | contentDescriptionBuilder.push(`${titleValue}`);
|
551 | }
|
552 | }
|
553 | if (view.accessibilityHint) {
|
554 | if (Trace.isEnabled()) {
|
555 | Trace.write(`${cls} - have accessibilityHint`, Trace.categories.Accessibility);
|
556 | }
|
557 | contentDescriptionBuilder.push(`${view.accessibilityHint}`);
|
558 | }
|
559 | const contentDescription = contentDescriptionBuilder.join('. ').trim().replace(/^\.$/, '');
|
560 | if (contentDescription) {
|
561 | if (Trace.isEnabled()) {
|
562 | Trace.write(`${cls} - set to "${contentDescription}"`, Trace.categories.Accessibility);
|
563 | }
|
564 | androidView.setContentDescription(contentDescription);
|
565 | }
|
566 | else {
|
567 | if (Trace.isEnabled()) {
|
568 | Trace.write(`${cls} - remove value`, Trace.categories.Accessibility);
|
569 | }
|
570 | androidView.setContentDescription(null);
|
571 | }
|
572 | view['_lastTitle'] = titleValue;
|
573 | view['_lastText'] = textValue;
|
574 | view._androidContentDescriptionUpdated = false;
|
575 | return contentDescription;
|
576 | }
|
577 |
|
\ | No newline at end of file |