1. Введение
Службы специальных возможностей — это функция платформы Android, предназначенная для предоставления пользователю альтернативной обратной связи при навигации от имени приложений, установленных на устройствах Android. Служба специальных возможностей может взаимодействовать с пользователем от имени приложения, например, преобразуя текст в речь или предоставляя тактильную обратную связь, когда пользователь наводит курсор на важную область экрана. В этом практическом занятии показано, как создать очень простую службу специальных возможностей.
Что такое служба обеспечения доступности?
Служба доступности помогает пользователям с ограниченными возможностями использовать устройства и приложения Android. Это давно существующая привилегированная служба, которая помогает пользователям обрабатывать информацию на экране и позволяет им осмысленно взаимодействовать с устройством.
Примеры распространенных услуг по обеспечению доступности
- Функция Switch Access позволяет пользователям Android с ограниченными возможностями передвижения взаимодействовать с устройствами, используя один или несколько переключателей.
- Голосовой доступ (бета-версия): позволяет пользователям Android с ограниченными возможностями передвижения управлять устройством с помощью голосовых команд.
- Talkback : программа для чтения с экрана, широко используемая пользователями с нарушениями зрения или слепотой.
Создание сервиса обеспечения доступности
Хотя Google предоставляет пользователям Android такие сервисы, как Switch Access, Voice Access и Talkback, эти сервисы не могут удовлетворить потребности всех пользователей с ограниченными возможностями. Поскольку у многих пользователей с ограниченными возможностями есть уникальные потребности, API Android для создания сервисов доступности являются открытыми, и разработчики могут свободно создавать сервисы доступности и распространять их через Play Store.
Что вы будете строить
В этом практическом занятии вы разработаете простой сервис, выполняющий несколько полезных функций с использованием API специальных возможностей. Если вы умеете писать базовые приложения для Android, вы сможете разработать аналогичный сервис.
API для обеспечения доступности обладает мощными возможностями: код создаваемого вами сервиса содержится всего в четырех файлах и занимает около 200 строк кода!
конечный пользователь
Вам предстоит создать сервис для гипотетического пользователя со следующими характеристиками:
- Пользователю трудно дотянуться до боковых кнопок на устройстве.
- Пользователю сложно прокручивать или проводить пальцем по экрану.
Подробности услуги
Ваш сервис разместит на экране глобальную панель действий. Пользователь сможет нажимать кнопки на этой панели для выполнения следующих действий:
- Выключите устройство, не нажимая на кнопку питания на боковой панели телефона.
- Регулируйте громкость, не нажимая на кнопки регулировки громкости на боковой панели телефона.
- Выполняйте действия прокрутки, не прокручивая страницу фактически.
- Выполните свайп, не используя при этом жест смахивания.
Что вам понадобится
В этом практическом задании предполагается, что вы будете использовать следующее:
- Компьютер, на котором запущена программа Android Studio.
- Терминал для выполнения простых команд оболочки.
- Устройство под управлением Android 7.0 (Nougat), подключенное к компьютеру, который вы будете использовать для разработки.
Давайте начнём!
2. Настройка
С помощью терминала создайте директорию, в которой будете работать. Перейдите в эту директорию.
Скачать код
Вы можете клонировать репозиторий, содержащий код для этого практического занятия:
git clone https://github.com/android/codelab-android-accessibility.git
В репозитории содержится несколько проектов Android Studio. Используя Android Studio, откройте GlobalActionBarService .
Запустите Android Studio, щелкнув значок Studio:

Выберите опцию «Импорт проекта (Eclipse ADT, Gradle и т. д.)» :

Перейдите в папку, куда вы клонировали исходный код, и выберите GlobalActionBarService.
Затем, используя терминал, перейдите в корневой каталог.
3. Понимание исходного кода
Изучите открытый вами проект.
Базовый шаблон для службы обеспечения доступности уже создан для вас. Весь код, который вы напишете в этом практическом занятии, ограничивается следующими четырьмя файлами:
- app/src/main/ AndroidManifest.xml
- app/src/main/res/layout/ action_bar.xml
- app/src/main/res/xml/ global_action_bar_service.xml
- app/src/main/java/com/example/android/globalactionbarservice/ GlobalActionBarService.java
Ниже представлено пошаговое описание содержимого каждого файла.
AndroidManifest.xml
Информация об услуге обеспечения доступности указана в манифесте:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.globalactionbarservice">
<application>
<service
android:name=".GlobalActionBarService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:exported="true">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/global_action_bar_service" />
</service>
</application>
</manifest>
В файле AndroidManifest.xml объявлены следующие три обязательных элемента:
- Разрешение на подключение к службе обеспечения доступности:
<service
...
android:permission = "android.permission.BIND_ACCESSIBILITY_SERVICE">
...
</service>
- Интент AccessibilityService :
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
- Расположение файла, содержащего метаданные для создаваемого вами сервиса:
<meta-data
...
android:resource="@xml/global_action_bar_service" />
</service>
global_action_bar_service.xml
Этот файл содержит метаданные для сервиса.
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canPerformGestures="true"
android:canRetrieveWindowContent="true" />
С помощью элемента <accessibility-service> были определены следующие метаданные:
- Тип обратной связи для этого сервиса (в этом практическом задании используется feedbackGeneric , что является хорошим вариантом по умолчанию).
- Флаги доступности для сервиса (в этом практическом задании используются флаги по умолчанию).
- Для предоставления услуги необходимы следующие возможности:
- Для выполнения жестов смахивания параметр android:canPerformGestures устанавливается в значение true .
- Для получения содержимого окна параметру android:canRetrieveWindowContent присваивается значение true .
GlobalActionBarService.java
Большая часть кода для службы специальных возможностей находится в файле GlobalActionBarService.java . Изначально этот файл содержит абсолютный минимум кода для службы специальных возможностей:
- Класс, наследующий AccessibilityService .
- Несколько обязательных переопределенных методов (в этом практическом задании они оставлены пустыми).
public class GlobalActionBarService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
}
@Override
public void onInterrupt() {
}
}
В ходе практического занятия вы добавите код в этот файл.
action_bar.xml
Сервис предоставляет пользовательский интерфейс с четырьмя кнопками, а файл разметки action_bar.xml содержит код для отображения этих кнопок:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
В этом файле пока содержится пустой LinearLayout . Разметку для кнопок вы добавите во время выполнения практического задания.
Запуск приложения
Убедитесь, что устройство подключено к компьютеру. Нажмите на зеленую иконку «Воспроизвести» .
Выберите пункт меню в верхней части экрана. Это должно запустить приложение, с которым вы работаете.
Перейдите в Настройки > Специальные возможности. На вашем устройстве установлена служба глобальной панели действий .

Щёлкните по пункту «Глобальная служба панели действий» и включите её. Вы должны увидеть следующее диалоговое окно с запросом разрешений:

Служба специальных возможностей запрашивает разрешение на отслеживание действий пользователя, получение содержимого окна и выполнение жестов от имени пользователя! При использовании сторонней службы специальных возможностей убедитесь, что вы действительно доверяете источнику !
Запуск сервиса мало что даст, поскольку мы еще не добавили никакой функциональности. Давайте начнем это делать.
4. Создание кнопок
Откройте файл action_bar.xml в папке res/layout . Добавьте разметку внутрь пустого в данный момент элемента LinearLayout :
<LinearLayout ...>
<Button
android:id="@+id/power"
android:text="@string/power"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/volume_up"
android:text="@string/volume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/scroll"
android:text="@string/scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/swipe"
android:text="@string/swipe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Это создаёт кнопки, которые пользователь будет нажимать для запуска действий на устройстве.
Откройте файл GlobalActionBarService.java и добавьте переменную для хранения макета панели действий:
public class GlobalActionBarService extends AccessibilityService {
FrameLayout mLayout;
...
}
Теперь добавьте метод onServiceStarted() :
public class GlobalActionBarService extends AccessibilityService {
FrameLayout mLayout;
@Override
protected void onServiceConnected() {
// Create an overlay and display the action bar
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
mLayout = new FrameLayout(this);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
lp.format = PixelFormat.TRANSLUCENT;
lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.TOP;
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.action_bar, mLayout);
wm.addView(mLayout, lp);
}
}
Код загружает макет и добавляет панель действий в верхней части экрана.
Метод onServiceConnected() выполняется, когда служба подключена. В этот момент служба специальных возможностей имеет все необходимые разрешения для корректной работы. Ключевое разрешение, которое вы будете использовать здесь, — это разрешение WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY . Это разрешение позволяет рисовать непосредственно на экране поверх существующего контента без необходимости использования сложной процедуры получения разрешений.
Жизненный цикл службы доступности
Жизненный цикл сервиса обеспечения доступности управляется исключительно системой и соответствует установленному жизненному циклу сервиса.
- Служба специальных возможностей запускается, когда пользователь явно включает её в настройках устройства.
- После того, как система подключится к службе, она вызывает метод onServiceConnected() . Этот метод может быть переопределен службами, которые хотят выполнить настройку после подключения.
- Служба специальных возможностей останавливается либо когда пользователь отключает её в настройках устройства, либо когда вызывается функция disableSelf() .
Запуск сервиса
Прежде чем запускать службу с помощью Android Studio, необходимо убедиться, что параметры запуска настроены правильно.
Отредактируйте параметры запуска (используйте меню «Запуск» вверху и перейдите в раздел «Редактировать параметры». Затем, используя выпадающее меню, измените параметр запуска с «Действие по умолчанию» на «Ничего».

Теперь вы сможете запустить службу с помощью Android Studio.
Нажмите на зеленую иконку «Воспроизвести» .
В строке меню в верхней части экрана. Затем перейдите в «Настройки» > «Специальные возможности» и включите службу глобальной панели действий.
Вы должны увидеть четыре кнопки, образующие пользовательский интерфейс сервиса, наложенные поверх содержимого, отображаемого на экране.

Теперь вы добавите функциональность к четырем кнопкам, чтобы пользователь мог, нажав на них, выполнять полезные действия.
5. Настройка кнопки питания
Добавьте метод configurePowerButton() в файл GlobalActionBarService.java :
private void configurePowerButton() {
Button powerButton = (Button) mLayout.findViewById(R.id.power);
powerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
performGlobalAction(GLOBAL_ACTION_POWER_DIALOG);
}
});
}
Для доступа к меню кнопки питания функция configurePowerButton() использует метод performGlobalAction() , предоставляемый классом AccessibilityService . Добавленный вами код прост: нажатие кнопки запускает обработчик события onClickListener() . Это вызывает метод performGlobalAction(GLOBAL_ACTION_POWER_DIALOG) и отображает диалоговое окно выбора питания пользователю.
Обратите внимание, что глобальные действия не привязаны к каким-либо представлениям. Нажатие кнопки «Назад», кнопки «Домой», кнопки «Недавние» — это другие примеры глобальных действий.
Теперь добавьте метод configurePowerButton() в конец метода onServiceConnected() :
@Override
protected void onServiceConnected() {
...
configurePowerButton();
}
Нажмите на зеленую иконку «Воспроизвести» .
В строке меню в верхней части экрана. Затем перейдите в «Настройки» > «Специальные возможности» и запустите службу глобальной панели действий.
Нажмите кнопку питания, чтобы отобразить диалоговое окно управления питанием.
6. Настройка кнопки регулировки громкости
Добавьте метод configureVolumeButton() в файл GlobalActionBarService.java :
private void configureVolumeButton() {
Button volumeUpButton = (Button) mLayout.findViewById(R.id.volume_up);
volumeUpButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
}
});
}
Метод configureVolumeButton() добавляет обработчик события onClickListener() , который срабатывает при нажатии пользователем кнопки регулировки громкости. Внутри этого обработчика configureVolumeButton() использует AudioManager для регулировки громкости потока.
Обратите внимание, что любой может регулировать громкость (для этого не обязательно быть службой поддержки людей с ограниченными возможностями).
Теперь добавьте метод configureVolumeButton() в конец метода onServiceConnected() :
@Override
protected void onServiceConnected() {
...
configureVolumeButton();
}
Нажмите на зеленую иконку «Воспроизвести» .
В строке меню в верхней части экрана. Затем перейдите в «Настройки» > «Специальные возможности» и запустите службу глобальной панели действий.
Нажмите кнопку регулировки громкости, чтобы изменить громкость.
Теперь гипотетический пользователь, которому не удается дотянуться до регуляторов громкости на боковой панели устройства, может использовать службу Global Action Bar Service для изменения (увеличения) громкости.
7. Настройка кнопки прокрутки
В этом разделе необходимо написать код для двух методов. Первый метод находит прокручиваемый узел, а второй выполняет прокрутку от имени пользователя.
Добавьте метод findScrollableNode в файл GlobalActionBarService.java :
private AccessibilityNodeInfo findScrollableNode(AccessibilityNodeInfo root) {
Deque<AccessibilityNodeInfo> deque = new ArrayDeque<>();
deque.add(root);
while (!deque.isEmpty()) {
AccessibilityNodeInfo node = deque.removeFirst();
if (node.getActionList().contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD)) {
return node;
}
for (int i = 0; i < node.getChildCount(); i++) {
deque.addLast(node.getChild(i));
}
}
return null;
}
Служба доступности не имеет доступа к фактическим элементам интерфейса на экране. Вместо этого она видит отражение того, что находится на экране, в виде дерева, состоящего из объектов AccessibilityNodeInfo . Эти объекты содержат информацию о представляемом ими элементе интерфейса (расположение элемента, любой связанный с ним текст, метаданные, добавленные для обеспечения доступности, действия, поддерживаемые элементом интерфейса и т. д.). Метод findScrollableNode() выполняет обход этого дерева в ширину, начиная с корневого узла. Если он находит прокручиваемый узел (т. е. узел, поддерживающий действие AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD ) , он возвращает его, в противном случае возвращает null.
Теперь добавьте метод configureScrollButton() в файл GlobalActionBarService.java :
private void configureScrollButton() {
Button scrollButton = (Button) mLayout.findViewById(R.id.scroll);
scrollButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AccessibilityNodeInfo scrollable = findScrollableNode(getRootInActiveWindow());
if (scrollable != null) {
scrollable.performAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId());
}
}
});
}
Этот метод создает обработчик события onClickListener() , который срабатывает при нажатии кнопки прокрутки. Он пытается найти прокручиваемый узел и, если ему это удается, выполняет действие прокрутки.
Теперь добавьте метод configureScrollButton() в метод onServiceConnected() :
@Override
protected void onServiceConnected() {
...
configureScrollButton();
}
Нажмите на зеленую иконку «Воспроизвести» .
В строке меню в верхней части экрана. Затем перейдите в «Настройки» > «Специальные возможности» и запустите службу глобальной панели действий.
Нажмите кнопку «Назад», чтобы перейти в «Настройки» > «Специальные возможности». Элементы в настройках специальных возможностей можно прокручивать, и нажатие кнопки «Прокрутка» выполняет действие прокрутки. Наш гипотетический пользователь, которому сложно легко выполнять действия прокрутки, теперь может использовать кнопку «Прокрутка» для прокрутки списка элементов.
8. Настройка кнопки «Провести пальцем»
Добавьте метод configureSwipeButton() в файл GlobalActionBarService.java :
private void configureSwipeButton() {
Button swipeButton = (Button) mLayout.findViewById(R.id.swipe);
swipeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Path swipePath = new Path();
swipePath.moveTo(1000, 1000);
swipePath.lineTo(100, 1000);
GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
gestureBuilder.addStroke(new GestureDescription.StrokeDescription(swipePath, 0, 500));
dispatchGesture(gestureBuilder.build(), null, null);
}
});
}
Метод configureSwipeButton() использует новый API, добавленный в версии N, который выполняет жесты от имени пользователя. Код использует объект GestureDescription для указания пути выполнения жеста (в этом практическом задании используются жестко заданные значения), а затем отправляет жест смахивания от имени пользователя с помощью метода dispatchGesture() сервиса AccessibilityService .
Теперь добавьте метод configureSwipeButton() в метод onServiceConnected() :
@Override
protected void onServiceConnected() {
...
configureSwipeButton();
}
Нажмите на зеленую иконку «Воспроизвести» .
В строке меню в верхней части экрана. Затем перейдите в «Настройки» > «Специальные возможности» и запустите службу глобальной панели действий.
Простейший способ проверить функцию свайпа — открыть приложение «Карты» , установленное на вашем телефоне. После загрузки карты, нажатие кнопки «Свайп» проведет пальцем по экрану вправо.
9. Резюме
Поздравляем! Вы создали простой и функциональный сервис для обеспечения доступности.
Вы можете расширить возможности этой услуги различными способами. Например:
- Сделайте панель действий перемещаемой (сейчас она просто располагается поверх экрана).
- Предоставьте пользователю возможность как увеличивать, так и уменьшать громкость.
- Разрешите пользователю проводить пальцем влево и вправо.
- Добавить поддержку дополнительных жестов, на которые может реагировать панель действий.
Данный практический пример охватывает лишь небольшую часть функциональности, предоставляемой API для обеспечения доступности. API также включает в себя следующие возможности (частичный список):
- Поддержка нескольких окон.
- Поддержка событий доступности (AccessibilityEvent ). При изменении пользовательского интерфейса службы доступности получают уведомления об этих изменениях с помощью объектов AccessibilityEvent. Затем служба может соответствующим образом реагировать на изменения пользовательского интерфейса.
- Возможность регулировать увеличение.
Этот практический урок поможет вам начать разработку сервиса для обеспечения доступности. Если вы знаете пользователя с конкретными проблемами доступности, которые вы хотели бы решить, вы можете создать сервис, который поможет этому пользователю.