1# AccessibilityExtensionAbility
2
3Accessibility Kit provides accessibility extension capabilities based on AccessibilityExtensionAbility in the ExtensionAbility framework. You can develop your accessibility extension services by applying the AccessibilityExtensionAbility template.
4
5## Creating an Accessibility Extension Service
6
7You can create an accessibility extension service by creating a project from scratch or adding the service to an existing project. Only one accessibility extension service can be created for a project.
8This example creates an accessibility extension service that implements the following functions:
9When the accessibility function is enabled, a right-then-down gesture obtains all nodes on the current screen, and a following left-then-down gesture obtains all nodes.
10
11### Creating a Project
12
13To create an independent accessibility extension service, create a project in the stage model of API version 9 or later in DevEco Studio.
14
15### Creating an AccessibilityExtAbility.ets File
16
17In the **ets** folder of a project, add the **AccessibilityExtAbility** folder and then create the **AccessibilityExtAbility.ets** file in the folder. You can implement some callbacks in the file to add service processing logic.
18
19```ts
20import { AccessibilityExtensionAbility, AccessibilityEvent } from '@kit.AccessibilityKit';
21import AccessibilityManager from './AccessibilityManager';
22
23class AccessibilityExtAbility extends AccessibilityExtensionAbility {
24    onConnect() {
25        console.info(`AccessibilityExtAbility onConnect`);
26        // Initialize the service logic.
27        AccessibilityManager.getInstance().onStart(this.context);
28    }
29
30    onDisconnect() {
31        console.info(`AccessibilityExtAbility onDisconnect`);
32        // Reclaim resources and exit the service logic.
33        AccessibilityManager.getInstance().onStop();
34    }
35
36    onAccessibilityEvent(accessibilityEvent: AccessibilityEvent) {
37        console.info(`AccessibilityExtAbility onAccessibilityEvent: ${JSON.stringify(accessibilityEvent)}`);
38        // Process the service logic based on the event information.
39        AccessibilityManager.getInstance().onEvent(accessibilityEvent);
40    }
41}
42
43export default AccessibilityExtAbility;
44```
45
46The APIs defined in the file are as follows.
47
48| Name| Description|
49| ---- | ---- |
50| onConnect(): void | Called when a connection with the extension service is set up.|
51| onDisconnect(): void | Called when the connection with the extension service is severed.|
52| onAccessibilityEvent(event: AccessibilityEvent): void | Called when an accessibility event occurs|
53
54Create the **AccessibilityManager.ets** file for storing the service logic code.
55```ts
56import {
57  AccessibilityElement,
58  AccessibilityEvent,
59  AccessibilityExtensionContext,
60  ElementAttributeKeys
61} from '@kit.AccessibilityKit';
62
63interface Rect {
64  left: number,
65  top: number,
66  width: number,
67  height: number,
68}
69
70// Attribute information to be queried
71let wantedAttribute: ElementAttributeKeys[] = ['bundleName', 'text', 'description', 'windowId'];
72type attributeValues = string | number | boolean | AccessibilityElement | AccessibilityElement[] | string[] | Rect;
73
74export default class AccessibilityManager {
75  private static instance: AccessibilityManager;
76  accessibleContext?: AccessibilityExtensionContext;
77  currentPageElementArray: Array<AccessibilityElement> | null = null;
78
79  static getInstance(): AccessibilityManager {
80    if (!AccessibilityManager.instance) {
81      AccessibilityManager.instance = new AccessibilityManager();
82    }
83    return AccessibilityManager.instance;
84  }
85
86  onStart(context: AccessibilityExtensionContext) {
87    console.info(`AccessibilityManager onStart`);
88    this.accessibleContext = context;
89  }
90
91  onStop() {
92    console.info(`AccessibilityManager onStop`);
93    this.accessibleContext = undefined;
94  }
95
96  onEvent(accessibilityEvent: AccessibilityEvent): void {
97    console.info(`AccessibilityManager onEvent`);
98    switch (accessibilityEvent.eventType) {
99      case 'rightThenDown':
100      // Obtain all nodes on the current screen.
101        this.getCurrentPageAllElement();
102        break;
103      case 'leftThenDown':
104      // Obtain all nodes.
105        this.printAllElementInfo();
106        break;
107      default:
108        break;
109    }
110  }
111
112  async getCurrentPageAllElement(): Promise<void> {
113    console.info(`AccessibilityManager getCurrentPageAllElement`);
114    let rootElement: AccessibilityElement;
115    if(!this.accessibleContext){
116      console.error(`AccessibilityManager accessibleContext undefined`);
117      return;
118    }
119    try {
120      rootElement = await this.accessibleContext?.getWindowRootElement();
121      this.currentPageElementArray = await this.getAttributeValue(rootElement, 'children') as AccessibilityElement[];
122    } catch (error) {
123      console.error(`AccessibilityExtAbility Failed to getWindowRootElement. Cause:${JSON.stringify(error)}`);
124    }
125  }
126
127  async getElementWantedInfo(accessibilityElement: AccessibilityElement, wantedAttribute: ElementAttributeKeys[]):
128    Promise<string | null> {
129    console.info(`AccessibilityUtils getElementAllInfo`);
130    if (accessibilityElement === null) {
131      console.error(`AccessibilityUtils accessibilityElement is null`);
132      return null;
133    }
134
135    let info = '';
136    let value: attributeValues | null;
137    for (let name of wantedAttribute) {
138      value = await this.getAttributeValue(accessibilityElement, name);
139      info = info.concat(name + ': ' + value + ' ');
140    }
141    return info;
142  }
143
144  async getAttributeValue(accessibilityElement: AccessibilityElement, key: ElementAttributeKeys):
145    Promise<attributeValues | null> {
146    console.info(`AccessibilityUtils getAttributeValue`);
147    let value: attributeValues;
148    let keys = await accessibilityElement.attributeNames();
149    let isExit = false;
150    for (let keyString of keys) {
151      if (key == keyString) {
152        isExit = true;
153      }
154    }
155    if (isExit) {
156      try {
157        value = await accessibilityElement.attributeValue(key);
158        return value;
159      } catch (error) {
160        console.error(`AccessibilityUtils Failed to get attributeValue of ${key} . Cause:  ${JSON.stringify(error)}`);
161      }
162    }
163    return null;
164  }
165
166  async printAllElementInfo(): Promise<void> {
167    console.info(`AccessibilityManager printAllElementInfo`);
168    if (this.currentPageElementArray === null || this.currentPageElementArray.length === 0) {
169      console.error(`AccessibilityManager currentPageElementArray is null`);
170      return;
171    }
172    let info: string | null = null;
173    for (let index = 0; index < this.currentPageElementArray.length; index++) {
174      info = await this.getElementWantedInfo(this.currentPageElementArray[index], wantedAttribute);
175      console.info(`AccessibilityManager element information: ${info}`);
176    }
177  }
178}
179```
180
181## Processing an Accessibility Event
182
183You can process the service logic for accessibility events through the **onAccessibilityEvent()** API. For details about the events, see [AccessibilityEvent](../reference/apis-accessibility-kit/js-apis-application-accessibilityExtensionAbility.md#accessibilityevent). In this example, the **rightThenDown** gesture is used.
184
185```ts
186onAccessibilityEvent(accessibilityEvent: AccessibilityEvent) {
187    console.info('AccessibilityExtAbility onAccessibilityEvent: ' + JSON.stringify(accessibilityEvent));
188    if (accessibilityEvent.eventType === 'rightThenDown') {
189        console.info('AccessibilityExtAbility onAccessibilityEvent: rightThenDown');
190        // TODO: Develop custom logic.
191    }
192}
193```
194For an accessibility event, you can use the APIs of the [AccessibilityExtensionContext](../reference/apis-accessibility-kit/js-apis-inner-application-accessibilityExtensionContext.md) module to configure the concerned information, obtain root information, and inject gestures.
195
196You can also process physical key events in the accessibility extension service. For details, see [onKeyEvent](../reference/apis-accessibility-kit/js-apis-application-accessibilityExtensionAbility.md#accessibilityextensionabilityonkeyevent).
197
198## Declaring the Capabilities of Accessibility Extension Service
199
200After developing the custom logic for an accessibility extension service, you must add the configuration information of the service to the corresponding module-level **module.json5** file in the project directory.
201
202The **srcEntry** tag indicates the path to the **extensionAbility**.
203The **label** tag indicates the name of the **extensionAbility** displayed in the list of installed extension services.
204The **description** tag indicates the help information about the **extensionAbility** displayed on the details page of the installed extension service.
205Make sure the value of the **type** tag is fixed at **accessibility**. Otherwise, the connection to the service will fail.
206
207```json
208"extensionAbilities": [
209  {
210    "name": "AccessibilityExtAbility",
211    "srcEntry": "./ets/AccessibilityExtAbility/AccessibilityExtAbility.ets",
212    "label": "$string:MainAbility_label",
213    "description": "$string:MainAbility_desc",
214    "type": "accessibility",
215    "metadata": [
216      {
217        "name": "ohos.accessibleability",
218        "resource": "$profile:accessibility_config"
219      }
220    ]
221  }
222]
223```
224In addition, **accessibility_config** is the specific configuration of the accessibility extension service. You need to create the **accessibility_config.json** file in **resources/base/profile/** and declare the [capability type](../reference/apis-accessibility-kit/js-apis-accessibility.md#capability) of the accessibility extension service in the file. In this example, the following declaration is required:
225```json
226{
227  "accessibilityCapabilities": [
228    "retrieve",
229    "gesture",
230    "touchGuide"
231  ]
232}
233```
234## Enabling a Custom Accessibility Extension Service
235
236You can enable or disable a custom accessibility extension service through the device settings.
237
2381. From the device settings screen, access the list of installed extended services under accessibility. If an extended service is not installed, it is grayed out, and "No service" is displayed.
239
2402. Locate the target extension service, and toggle on or off the switch to enable or disable it.
241
2423. If you opt to enable a service, a security reminder is displayed. Wait until the countdown ends and then select the check box indicating that you are aware of and willing to assume the listed risks. After that, you can toggle off the switch to the extended service.
243