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 FindAccessibilityNodeInfoById(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 ExecuteAccessibilityAction(int64_t elementId, ArkUI_Accessibility_ActionType action, ArkUI_AccessibilityActionArguments *actionArguments, int32_t requestId)
71{
72    // ...
73    // Obtain action argument content and combine it with action to determine the operation to be processed.
74    char* actionArgumentValue;
75    OH_ArkUI_FindAccessibilityActionArgumentByKey(actionArguments, key.c_str(), &actionArgumentValue);
76
77    // Perform operations on the specified component node.
78    ret = doAction(elementId, action, actionArgumentValue);
79    if (ret != 0) {
80        return;
81    }
82    // 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.
83    // ...
84    // Specify that the component node that reports the event is node.
85    // 1. Call OH_ArkUI_CreateAccessibilityEventInfo to create an ArkUI_AccessibilityEventInfo instance.
86    ArkUI_AccessibilityEventInfo *eventInfo = OH_ArkUI_CreateAccessibilityEventInfo();
87    if (eventInfo == nullptr) {
88        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, LOG_PRINT_TEXT, "[requestId: %{public}d]DispatchTouchEventCB: Unable to create accessibility eventInfo", requestId);
89        return;
90    }
91    // 2. Call OH_ArkUI_CreateAccessibilityElementInfo to create an ArkUI_AccessibilityElementInfo instance.
92    ArkUI_AccessibilityElementInfo *elementInfo = OH_ArkUI_CreateAccessibilityElementInfo();
93    if (elementInfo == nullptr) {
94        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, LOG_PRINT_TEXT, "[requestId: %{public}d]DispatchTouchEventCB: Unable to create accessibility elementInfo", requestId);
95        return;
96    }
97    // 3. Enter the element content.
98    // Set the element member content.
99    OH_ArkUI_AccessibilityElementInfoSetElementId(element, nodes[i].id);
100    OH_ArkUI_AccessibilityElementInfoSetComponentType(element, nodes[i].type);
101
102    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, LOG_PRINT_TEXT, "[requestId: %{public}d]DispatchTouchEventCB: send accessibility event", requestId);
103    // 4. Set eventType based on the current action.
104    // ...
105    SendAccessibilityAsyncEvent(eventInfo, elementInfo, eventType);
106    // 5. Destroy the memory for eventInfo and elementInfo.
107    OH_ArkUI_DestoryAccessibilityElementInfo(elementInfo);
108    OH_ArkUI_DestoryAccessibilityEventInfo(eventInfo);
109    // ...
110}
111void FillEvent(ArkUI_AccessibilityEventInfo *eventInfo, ArkUI_AccessibilityElementInfo *elementInfo, ArkUI_AccessibilityEventType eventType)
112{
113    if (eventInfo == nullptr) {
114        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_TEXT, "eventInfo is null");
115        return;
116    }
117    if (elementInfo == nullptr) {
118        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_TEXT, "elementInfo is null");
119        return;
120    }
121    OH_ArkUI_AccessibilityEventSetEventType(eventInfo, eventType);
122
123    OH_ArkUI_AccessibilityEventSetElementInfo(eventInfo, elementInfo);
124
125}
126void SendAccessibilityAsyncEvent(ArkUI_AccessibilityEventInfo *eventInfo, ArkUI_AccessibilityElementInfo *elementInfo, ArkUI_AccessibilityEventType eventType)
127{
128    // 1. Enter the event content.
129    FillEvent(eventInfo, elementInfo, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_STATE_UPDATE);
130    // 2. Callback
131    auto callback = [](int32_t errorCode){
132         OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, LOG_PRINT_TEXT, "result: %{public}d", errorCode);
133    }
134    // 3. Call the API to send the event to the OpenHarmony side.
135    OH_ArkUI_SendAccessibilityAsyncEvent(provider_, eventInfo, callback)
136}
137```
138
139
140
141```C
142int32_t ClearFocusedFocusAccessibilityNode()
143{
144	// Find the currently focused component and clear its focus state.
145    // ...
146    // Accessibility focus state
147    node.accessibilityFocused = false;
148    // Component focus state
149    node.foucsed = false;
150    // ...
151}
152```
153
154
155
156```C
157int32_t GetAccessibilityNodeCursorPosition(int64_t elementId, int32_t requestId, int32_t* index)
158{
159	// Obtain the cursor position of the text component and return it.
160    // Search for the corresponding component node.
161    // ...
162    *index = node.cursorPosition;
163    // ...
164}
165```
166
167
168
1693. Register the accessibility callback functions using the **XComponent** handle.
170
171```C
172void PluginRender::RegisterAccessibility(OH_NativeXComponent* nativeXComponent)
173{
174	//...
175    // 1. Obtain the provider instance and provide it to the function for return.
176    int32_t ret = OH_NativeXComponent_GetNativeAccessibilityProvider(nativeXComponent, &provider_);
177    if (provider_ == nullptr) {
178        return;
179    }
180    // 2. Register the callback functions, such as FindAccessibilityNodeInfosById, which need to be implemented by the third party.
181    accessibilityProviderCallbacks_ = new ArkUI_AccessibilityProviderCallbacks();
182    accessibilityProviderCallbacks_->findAccessibilityNodeInfosById = FindAccessibilityNodeInfosById;
183    accessibilityProviderCallbacks_->findAccessibilityNodeInfosByText = FindAccessibilityNodeInfosByText;
184    accessibilityProviderCallbacks_->findFocusedAccessibilityNode = FindFocusedAccessibilityNode;
185    accessibilityProviderCallbacks_->executeAccessibilityAction = ExecuteAccessibilityAction;
186    accessibilityProviderCallbacks_->clearFocusedFocusAccessibilityNode = ClearFocusedFocusAccessibilityNode;
187    accessibilityProviderCallbacks_->getAccessibilityNodeCursorPosition = GetAccessibilityNodeCursorPosition;
188    ret = OH_ArkUI_AccessibilityProviderRegisterCallback(provider_, accessibilityProviderCallbacks_);
189    if (ret != 0) {
190        return;
191    }
192}
193```
194
195
196
1974. When components change, proactively send events. For details, see [ArkUI_AccessibilityEventType](../reference/apis-arkui/arkui_native_interface_accessibility.md#arkui_accessibilityeventtype).
198
199If 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).
200
201```C
202// Define the DispatchTouchEventCB() function, which is triggered to respond to a touch event.
203void DispatchTouchEventCB(OH_NativeXComponent *component, void *window)
204{
205	// ...
206	// Obtain the ID of the XComponent.
207	char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' };
208	uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
209	if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
210		OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback",
211			"DispatchTouchEventCB: Unable to get XComponent id");
212		return;
213	}
214
215    // Check whether an accessibility provider has been registered.
216    if (provider_ != nullptr) {
217
218        // 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.
219        // ...
220        // Specify that the component node that reports the event is node.
221        // 1. Call OH_ArkUI_CreateAccessibilityEventInfo to create an ArkUI_AccessibilityEventInfo instance.
222        ArkUI_AccessibilityEventInfo *eventInfo = OH_ArkUI_CreateAccessibilityEventInfo();
223        if (eventInfo == nullptr) {
224            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback",
225			"DispatchTouchEventCB: Unable to create accessibility eventInfo");
226            return;
227        }
228        // 2. Call OH_ArkUI_CreateAccessibilityElementInfo to create an ArkUI_AccessibilityElementInfo instance.
229        ArkUI_AccessibilityElementInfo *elementInfo = OH_ArkUI_CreateAccessibilityElementInfo();
230        if (elementInfo == nullptr) {
231            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback",
232			"DispatchTouchEventCB: Unable to create accessibility elementInfo");
233            return;
234        }
235        // 3. Enter the element content.
236        // Set the element member content.
237    	OH_ArkUI_AccessibilityElementInfoSetElementId(element, nodes[i].id);
238    	OH_ArkUI_AccessibilityElementInfoSetComponentType(element, nodes[i].type);
239        // ...
240
241        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback",
242			"DispatchTouchEventCB: send accessibility event");
243        // 4. Send the page update event.
244        SendAccessibilityAsyncEvent(eventInfo, elementInfo, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_STATE_UPDATE);
245        // 5. If the current processing has caused a change in the position of the focused component, send the focus position change event.
246        SendAccessibilityAsyncEvent(eventInfo, elementInfo, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_FOCUS_NODE_UPDATE);
247        // 6. Destroy the memory for eventInfo and elementInfo.
248        OH_ArkUI_DestoryAccessibilityElementInfo(elementInfo);
249        OH_ArkUI_DestoryAccessibilityEventInfo(eventInfo);
250    }
251
252	std::string id(idStr);
253	PluginRender *render = PluginRender::GetInstance(id);
254	if (render != nullptr) {
255		// Encapsulate the OnTouchEvent method.
256		render->OnTouchEvent(component, window);
257	}
258}
259
260void FillEvent(ArkUI_AccessibilityEventInfo *eventInfo, ArkUI_AccessibilityElementInfo *elementInfo, ArkUI_AccessibilityEventType eventType)
261{
262    if (eventInfo == nullptr) {
263        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_TEXT, "eventInfo is null");
264        return;
265    }
266    if (elementInfo == nullptr) {
267        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_TEXT, "elementInfo is null");
268        return;
269    }
270    // 1. Set the event type.
271    OH_ArkUI_AccessibilityEventSetEventType(eventInfo, eventType);
272    // 2. Set the node component information for the event being sent.
273    OH_ArkUI_AccessibilityEventSetElementInfo(eventInfo, elementInfo);
274
275}
276void SendAccessibilityAsyncEvent(ArkUI_AccessibilityEventInfo *eventInfo, ArkUI_AccessibilityElementInfo *elementInfo, ArkUI_AccessibilityEventType eventType)
277{
278    // 1. Enter the event content.
279    FillEvent(eventInfo, elementInfo, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_STATE_UPDATE);
280    // 2. Create a callback function to obtain the event sending result.
281    auto callback = [](int32_t errorCode){
282         OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, LOG_PRINT_TEXT, "result: %{public}d", errorCode);
283    }
284    // 3. Call the API to send the event to the accessibility subsystem.
285    OH_ArkUI_SendAccessibilityAsyncEvent(provider_, eventInfo, callback)
286}
287```
288
2895. When the integration is successful, the accessibility features can be enabled.
290
291![accessibility](./figures/accessibility-pic.png)
292