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 328