• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Integrating Accessibility Through XComponent
2
3The NDK provides third-party platforms accessed through **XComponent** with APIs for integrating accessibility, allowing components of these platforms to be accessible within ArkUI.
4
5First, you need to use the [OH_NativeXComponent_GetNativeAccessibilityProvider](../reference/apis-arkui/_o_h___native_x_component.md#oh_nativexcomponent_getnativeaccessibilityprovider) API of the **XComponent** to obtain the accessibility provider. Then, call [OH_ArkUI_AccessibilityProviderRegisterCallback](../reference/apis-arkui/arkui_native_interface_accessibility.md#oh_arkui_accessibilityproviderregistercallback) to register the required callback functions for accessibility: [ArkUI_AccessibilityProviderCallbacks](../reference/apis-arkui/arkui_native_interface_accessibility.md#arkui_accessibilityprovidercallbacks).
6
7To deliver a smooth accessibility service experience, third-party applications must adapt to the [actions](../reference/apis-arkui/arkui_native_interface_accessibility.md#arkui_accessibility_actiontype) sent by the accessibility subsystem and send [accessibility events](../reference/apis-arkui/arkui_native_interface_accessibility.md#arkui_accessibilityeventtype) to the accessibility subsystem in response to component interactions.
8
9> **NOTE**
10>
11> - When implementing the callback query API of [OH_ArkUI_AccessibilityProviderRegisterCallback](../reference/apis-arkui/arkui_native_interface_accessibility.md#oh_arkui_accessibilityproviderregistercallback), each accessibility node information found is created and allocated memory with [OH_ArkUI_AddAndGetAccessibilityElementInfo](../reference/apis-arkui/arkui_native_interface_accessibility.md#oh_arkui_addandgetaccessibilityelementinfo) and added to the specified element list.
12> - When sending events with [OH_ArkUI_SendAccessibilityAsyncEvent](../reference/apis-arkui/arkui_native_interface_accessibility.md#oh_arkui_sendaccessibilityasyncevent), you need to create [ArkUI_AccessibilityEventInfo](../reference/apis-arkui/arkui_native_interface_accessibility.md#arkui_accessibilityeventinfo) with [OH_ArkUI_CreateAccessibilityEventInfo](../reference/apis-arkui/arkui_native_interface_accessibility.md#oh_arkui_createaccessibilityeventinfo) and [ArkUI_AccessibilityElementInfo](../reference/apis-arkui/arkui_native_interface_accessibility.md#arkui_accessibilityelementinfo) with [OH_ArkUI_CreateAccessibilityElementInfo](../reference/apis-arkui/arkui_native_interface_accessibility.md#oh_arkui_createaccessibilityelementinfo). After usage, you must call [OH_ArkUI_DestoryAccessibilityEventInfo](../reference/apis-arkui/arkui_native_interface_accessibility.md#oh_arkui_destoryaccessibilityeventinfo) and [OH_ArkUI_DestoryAccessibilityElementInfo](../reference/apis-arkui/arkui_native_interface_accessibility.md#oh_arkui_destoryaccessibilityelementinfo) to release memory.
13> - When logging within callback functions, include the provided **requestId** parameter to link logs to a specific interaction process. This practice facilitates indexing and querying and aids in troubleshooting and pinpointing issues.
14
15## Integrating Accessibility
16
17The following example shows how to integrate accessibility capabilities. After integration, when accessibility features are enabled, third-party rendering components of the **XComponent** can be integrated to achieve accessible interactions.
18
191. Follow the instructions in [Custom Rendering (XComponent)](napi-xcomponent-guidelines.md) to create the prerequisite project.
20
212. Implement callback functions based on the API definition.
22
23```c
24int32_t FindAccessibilityNodeInfosById(int64_t elementId, ArkUI_AccessibilitySearchMode mode, int32_t requestId, ArkUI_AccessibilityElementInfoList* elementList)
25{
26    // Query the element information list based on mode.
27	if (elementList == nullptr) {
28        return OH_NATIVEXCOMPONENT_RESULT_FAILED;
29    }
30
31    // Call the API of the third-party platform to search for the nodes that meet the mode requirements.
32    //...
33    // nodes is the search result.
34    int size = sizeof(nodes) / sizeof(nodes[0]);
35    for (int i = 0; i < size; i++) {
36        // Obtain the element structure.
37        element = OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList);
38        // Set the element member content.
39        OH_ArkUI_AccessibilityElementInfoSetElementId(element, nodes[i].id);
40        OH_ArkUI_AccessibilityElementInfoSetComponentType(element, nodes[i].type);
41        // ...
42    }
43	// ...
44}
45```
46
47
48
49```c
50int32_t FindNextFocusAccessibilityNode(int64_t elementId, ArkUI_AccessibilityFocusType focusType, int32_t requestId, ArkUI_AccessibilityElementInfo* elementinfo)
51{
52    // Query the element information list based on mode. For details, see the API description.
53	if (elementinfo == nullptr) {
54        return OH_NATIVEXCOMPONENT_RESULT_FAILED;
55    }
56
57    // Call the API of the third-party platform to search for the nodes that meet the search criteria.
58    //...
59    // nodes is the search result.
60    // Set the element member content.
61    OH_ArkUI_AccessibilityElementInfoSetElementId(element, nodes[i].id);
62    OH_ArkUI_AccessibilityElementInfoSetComponentType(element, nodes[i].type);
63    // ...
64}
65```
66
67
68
69```c
70int32_t FindAccessibilityNodeInfosByText(int64_t elementId, const char *text, int32_t requestId, ArkUI_AccessibilityElementInfoList* elementList)
71{
72    if (elementList == nullptr) {
73        return OH_NATIVEXCOMPONENT_RESULT_FAILED;
74    }
75
76    ArkUI_AccessibilityElementInfo *elementInfo = OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList);
77
78    // The third-party platform needs to set elementInfo.
79
80    if (elementInfo == nullptr) {
81        return OH_NATIVEXCOMPONENT_RESULT_FAILED;
82    }
83    return OH_NATIVEXCOMPONENT_RESULT_SUCCESS;
84}
85```
86
87
88
89```c
90int32_t FindFocusedAccessibilityNode(int64_t elementId, ArkUI_AccessibilityFocusType focusType, int32_t requestId, ArkUI_AccessibilityElementInfo *elementInfo)
91{
92    if (elementInfo == nullptr) {
93        return OH_NATIVEXCOMPONENT_RESULT_FAILED;
94    }
95
96    // The third-party platform needs to set elementInfo.
97
98    return OH_NATIVEXCOMPONENT_RESULT_SUCCESS;
99}
100```
101
102
103
104```C
105int32_t ExecuteAccessibilityAction(int64_t elementId, ArkUI_Accessibility_ActionType action, ArkUI_AccessibilityActionArguments *actionArguments, int32_t requestId)
106{
107    // ...
108    // Obtain action argument content and combine it with action to determine the operation to be processed.
109    char* actionArgumentValue;
110    OH_ArkUI_FindAccessibilityActionArgumentByKey(actionArguments, key.c_str(), &actionArgumentValue);
111
112    // Perform operations on the specified component node.
113    ret = doAction(elementId, action, actionArgumentValue);
114    if (ret != 0) {
115        return;
116    }
117    // Determine the current operation type and return the corresponding event result. Each operation corresponds to a unique event. For details, see the ArkUI_AccessibilityEventType description.
118    // ...
119    // Specify that the component node that reports the event is node.
120    // 1. Call OH_ArkUI_CreateAccessibilityEventInfo to create an ArkUI_AccessibilityEventInfo instance.
121    ArkUI_AccessibilityEventInfo *eventInfo = OH_ArkUI_CreateAccessibilityEventInfo();
122    if (eventInfo == nullptr) {
123        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, LOG_PRINT_TEXT, "[requestId: %{public}d]DispatchTouchEventCB: Unable to create accessibility eventInfo", requestId);
124        return;
125    }
126    // 2. Call OH_ArkUI_CreateAccessibilityElementInfo to create an ArkUI_AccessibilityElementInfo instance.
127    ArkUI_AccessibilityElementInfo *elementInfo = OH_ArkUI_CreateAccessibilityElementInfo();
128    if (elementInfo == nullptr) {
129        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, LOG_PRINT_TEXT, "[requestId: %{public}d]DispatchTouchEventCB: Unable to create accessibility elementInfo", requestId);
130        return;
131    }
132    // 3. Enter the element content.
133    // Set the element member content.
134    OH_ArkUI_AccessibilityElementInfoSetElementId(element, nodes[i].id);
135    OH_ArkUI_AccessibilityElementInfoSetComponentType(element, nodes[i].type);
136
137    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, LOG_PRINT_TEXT, "[requestId: %{public}d]DispatchTouchEventCB: send accessibility event", requestId);
138    // 4. Set eventType based on the current action.
139    // ...
140    SendAccessibilityAsyncEvent(eventInfo, elementInfo, eventType);
141    // 5. Destroy the memory for eventInfo and elementInfo.
142    OH_ArkUI_DestoryAccessibilityElementInfo(elementInfo);
143    OH_ArkUI_DestoryAccessibilityEventInfo(eventInfo);
144    // ...
145}
146void FillEvent(ArkUI_AccessibilityEventInfo *eventInfo, ArkUI_AccessibilityElementInfo *elementInfo, ArkUI_AccessibilityEventType eventType)
147{
148    if (eventInfo == nullptr) {
149        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_TEXT, "eventInfo is null");
150        return;
151    }
152    if (elementInfo == nullptr) {
153        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_TEXT, "elementInfo is null");
154        return;
155    }
156    OH_ArkUI_AccessibilityEventSetEventType(eventInfo, eventType);
157
158    OH_ArkUI_AccessibilityEventSetElementInfo(eventInfo, elementInfo);
159
160}
161void SendAccessibilityAsyncEvent(ArkUI_AccessibilityEventInfo *eventInfo, ArkUI_AccessibilityElementInfo *elementInfo, ArkUI_AccessibilityEventType eventType)
162{
163    // 1. Enter the event content.
164    FillEvent(eventInfo, elementInfo, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_STATE_UPDATE);
165    // 2. Callback
166    auto callback = [](int32_t errorCode){
167         OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, LOG_PRINT_TEXT, "result: %{public}d", errorCode);
168    }
169    // 3. Call the API to send the event to the OpenHarmony side.
170    OH_ArkUI_SendAccessibilityAsyncEvent(provider_, eventInfo, callback)
171}
172```
173
174
175
176```C
177int32_t ClearFocusedFocusAccessibilityNode()
178{
179	// Find the currently focused component and clear its focus state.
180    // ...
181    // Accessibility focus state
182    node.accessibilityFocused = false;
183    // Component focus state
184    node.foucsed = false;
185    // ...
186}
187```
188
189
190
191```C
192int32_t GetAccessibilityNodeCursorPosition(int64_t elementId, int32_t requestId, int32_t* index)
193{
194	// Obtain the cursor position of the text component and return it.
195    // Search for the corresponding component node.
196    // ...
197    *index = node.cursorPosition;
198    // ...
199}
200```
201
202
203
2043. Register the accessibility callback functions using the **XComponent** handle.
205
206```C
207void PluginRender::RegisterAccessibility(OH_NativeXComponent* nativeXComponent)
208{
209	//...
210    // 1. Obtain the provider instance and provide it to the function for return.
211    int32_t ret = OH_NativeXComponent_GetNativeAccessibilityProvider(nativeXComponent, &provider_);
212    if (provider_ == nullptr) {
213        return;
214    }
215    // 2. Register the callback functions, such as FindAccessibilityNodeInfosById, which need to be implemented by the third party.
216    accessibilityProviderCallbacks_ = new ArkUI_AccessibilityProviderCallbacks();
217    accessibilityProviderCallbacks_->findAccessibilityNodeInfosById = FindAccessibilityNodeInfosById;
218    accessibilityProviderCallbacks_->findAccessibilityNodeInfosByText = FindAccessibilityNodeInfosByText;
219    accessibilityProviderCallbacks_->findFocusedAccessibilityNode = FindFocusedAccessibilityNode;
220    accessibilityProviderCallbacks_->findNextFocusAccessibilityNode = FindNextFocusAccessibilityNode;
221    accessibilityProviderCallbacks_->executeAccessibilityAction = ExecuteAccessibilityAction;
222    accessibilityProviderCallbacks_->clearFocusedFocusAccessibilityNode = ClearFocusedFocusAccessibilityNode;
223    accessibilityProviderCallbacks_->getAccessibilityNodeCursorPosition = GetAccessibilityNodeCursorPosition;
224    ret = OH_ArkUI_AccessibilityProviderRegisterCallback(provider_, accessibilityProviderCallbacks_);
225    if (ret != 0) {
226        return;
227    }
228}
229```
230
231
232
2334. When components change, proactively send events. For details, see [ArkUI_AccessibilityEventType](../reference/apis-arkui/arkui_native_interface_accessibility.md#arkui_accessibilityeventtype).
234
235If a touch event causes a page change, send the following events: **ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_STATE_UPDATE** (page change event) and **ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_FOCUS_NODE_UPDATE** (focus position change event).
236
237```C
238// Define the DispatchTouchEventCB() function, which is triggered to respond to a touch event.
239void DispatchTouchEventCB(OH_NativeXComponent *component, void *window)
240{
241	// ...
242	// Obtain the ID of the XComponent.
243	char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' };
244	uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
245	if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
246		OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback",
247			"DispatchTouchEventCB: Unable to get XComponent id");
248		return;
249	}
250
251    // Check whether an accessibility provider has been registered.
252    if (provider_ != nullptr) {
253
254        // Check whether the current touch event causes any change in the page and the position of the focused component. If changes occur, report accessibility events to notify accessibility services and applications.
255        // ...
256        // Specify that the component node that reports the event is node.
257        // 1. Call OH_ArkUI_CreateAccessibilityEventInfo to create an ArkUI_AccessibilityEventInfo instance.
258        ArkUI_AccessibilityEventInfo *eventInfo = OH_ArkUI_CreateAccessibilityEventInfo();
259        if (eventInfo == nullptr) {
260            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback",
261			"DispatchTouchEventCB: Unable to create accessibility eventInfo");
262            return;
263        }
264        // 2. Call OH_ArkUI_CreateAccessibilityElementInfo to create an ArkUI_AccessibilityElementInfo instance.
265        ArkUI_AccessibilityElementInfo *elementInfo = OH_ArkUI_CreateAccessibilityElementInfo();
266        if (elementInfo == nullptr) {
267            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback",
268			"DispatchTouchEventCB: Unable to create accessibility elementInfo");
269            return;
270        }
271        // 3. Enter the element content.
272        // Set the element member content.
273    	OH_ArkUI_AccessibilityElementInfoSetElementId(element, nodes[i].id);
274    	OH_ArkUI_AccessibilityElementInfoSetComponentType(element, nodes[i].type);
275        // ...
276
277        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback",
278			"DispatchTouchEventCB: send accessibility event");
279        // 4. Send the page update event.
280        SendAccessibilityAsyncEvent(eventInfo, elementInfo, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_STATE_UPDATE);
281        // 5. If the current processing has caused a change in the position of the focused component, send the focus position change event.
282        SendAccessibilityAsyncEvent(eventInfo, elementInfo, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_FOCUS_NODE_UPDATE);
283        // 6. Destroy the memory for eventInfo and elementInfo.
284        OH_ArkUI_DestoryAccessibilityElementInfo(elementInfo);
285        OH_ArkUI_DestoryAccessibilityEventInfo(eventInfo);
286    }
287
288	std::string id(idStr);
289	PluginRender *render = PluginRender::GetInstance(id);
290	if (render != nullptr) {
291		// Encapsulate the OnTouchEvent method.
292		render->OnTouchEvent(component, window);
293	}
294}
295
296void FillEvent(ArkUI_AccessibilityEventInfo *eventInfo, ArkUI_AccessibilityElementInfo *elementInfo, ArkUI_AccessibilityEventType eventType)
297{
298    if (eventInfo == nullptr) {
299        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_TEXT, "eventInfo is null");
300        return;
301    }
302    if (elementInfo == nullptr) {
303        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_TEXT, "elementInfo is null");
304        return;
305    }
306    // 1. Set the event type.
307    OH_ArkUI_AccessibilityEventSetEventType(eventInfo, eventType);
308    // 2. Set the node component information for the event being sent.
309    OH_ArkUI_AccessibilityEventSetElementInfo(eventInfo, elementInfo);
310
311}
312void SendAccessibilityAsyncEvent(ArkUI_AccessibilityEventInfo *eventInfo, ArkUI_AccessibilityElementInfo *elementInfo, ArkUI_AccessibilityEventType eventType)
313{
314    // 1. Enter the event content.
315    FillEvent(eventInfo, elementInfo, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_STATE_UPDATE);
316    // 2. Create a callback function to obtain the event sending result.
317    auto callback = [](int32_t errorCode){
318         OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, LOG_PRINT_TEXT, "result: %{public}d", errorCode);
319    }
320    // 3. Call the API to send the event to the accessibility subsystem.
321    OH_ArkUI_SendAccessibilityAsyncEvent(provider_, eventInfo, callback)
322}
323```
324
3255. When the integration is successful, the accessibility features can be enabled.
326
327![accessibility](./figures/accessibility-pic.png)
328