- Keyguardmanager.keyguardlock
- Ввод пароля через shell
- Включить блокировку экрана
- Готовые решения
- Измените время, после которого телефон блокируется
- Использование keyguardlock
- Не нужно разблокировать экран для небольших платежей
- Немного о самих метках
- Нет простой возможности разблокировки
- Пишем обходные пути
- Плюсы:
- Сделаем свою реализацию
- Сканер меток работает не всегда
- Установка флага для окна activity
- Флаги окна
Keyguardmanager.keyguardlock
Этот класс содержит 2 метода: disableKeyguard() и reenableKeyguard(). Первый метод разблокирует только не защищёный экран. Если экран защищён каким-либо методом, то вызов будет проигнорирован. Метод reenableKeyguard() необходимо вызвать для повторной блокировки экрана, иначе блокировщик не будет запускаться после его выключения.
Минусы данного решения: нельзя разблокировать экран защищённый, допустим, паролем да ещё и надо по какому-то событию вызывать перезапуск экрана блокировки. Вдобавок данный класс является устаревшим начиная с API 13, так что на него не стоит надеяться.
Ввод пароля через shell
Этот способ я придумал первым так как он достаточно прост, но требует root. В Андроиде с shell-а можно вызвать команду «input», которая позволяет вводить текст и эмулировать нажатия клавиш. Для ввода текста используется такой синтаксис:
input text "type your text here"
Эмуляция нажатий клавиш производится с помощью такой команды:
input keyevent KEYCODE
Список кодов клавиш можно найти
Алгоритм разблокировки у данного метода очень прост:
- Пользователь сканирует метку, запускается наше Activity.
- Вводим пароль с помощью shell команды «input», и с её же помощью посылаем код клавиши Enter.
Включить блокировку экрана
- Откройте на телефоне приложение Настройки.
- Нажмите Безопасность.
- Чтобы выбрать тип блокировки экрана, нажмите Блокировка экрана.
Если у вас уже активна блокировка, прежде чем выбрать другой тип необходимо ввести PIN-код, графический ключ или пароль.
- Выберите тип блокировки, который вы хотите использовать. Следуйте инструкциям на экране.
Готовые решения
Единственным готовым решением, которое я нашёл, для реализации разблокировки девайса с помощью метки, является программа
. Она платная, а бесплатной версии нет. Посмотрев видео на его странице в Google Play, я сразу для себя решил, что ЭТО не стоит своих денег. Всё реализовано простейшим способом:
- Пользователь включает экран устройства и видит стандартный блокировщик экрана.
- Он его разблокирует.
- Появляется Activity NFCSecure, которое делает вид, что надёжно блокирует доступ к устройству (при нажатии на иконку разблокировки страница почему-то мигает, что не вселяет доверия).
- Прикладываем метку и окно закрывается.
Даже, если предположить, что это окно блокирует любые попытки физически добраться до стандартного лаунчера (сенсорные кнопки, физические кнопки, жест по статусной строке), оно ни в коем случае не реализует всю ту защиту, которую предоставляет стандартный экран блокировки.
В общем это приложение достаточно дырявое и защиту сравнимую со стандартным экраном блокировки оно не предоставляет.
Измените время, после которого телефон блокируется
Вы можете оплатить по телефону, когда он разблокирован.
Настройте его так, чтобы он быстрее блокировался для повышения безопасности:
- На вашем телефоне Android откройте приложение «Настройки».
- Нажмите Блокировка экрана и Безопасность → Блокировка экрана → Блокировать автоматически.
- Укажите, через какое время телефон должен блокироваться.
Использование keyguardlock
Следующий метод использует устаревшее API, но тем не менее успешно выполняет свою задачу на Android 4.3. Так же как и в предыдущем методе нам придётся очистить пароль, чтобы разблокировка сработала.
Здесь алгоритм сложнее и с первого взгляда достаточно не стабилен (на практике всё гораздо лучше):
- Пользователь сканирует метку, запускается наше Activity.
- Чистим пароль:
((DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE)).resetPassword("", 0).
- Разблокируем экран:
KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(Activity.KEYGUARD_SERVICE);
KeyguardLock keyguardLock = keyguardManager.newKeyguardLock("nfcunlocker");
keyguardLock.disableKeyguard();
- Запускаем сервис, который в фоновом режиме создаст BroadcastReceiver, который будет принимать событие выключения экрана:
ScreenReceiver screenReceiver = new ScreenReceiver();
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(mReceiver, filter);
- Как только получено событие оповещающее о том, что экран выключен — включаем блокировку и восстанавливаем пароль.
Данный метод работает достаточно стабильно, но пользуется устаревшим API.
Не нужно разблокировать экран для небольших платежей
Для большинства транзакций вам потребуется разблокировать телефон. Тем не менее, это не обязательно, когда вы делаете небольшие платежи.
Важно: вы можете совершать ограниченное количество транзакций без разблокировки телефона. Когда лимит закончится, ваш телефон должен быть разблокирован.
Платежные ограничения Google Pay, которые не требуют разблокировки мобильного устройства:
страна | сумма |
---|---|
Австралия | 100 AUD |
Бельгия | 25 Евро |
Бразилия | 50 BRL |
Канада | 100 CAD |
Чили | 12 000 CLP для кредитных карт |
Хорватия | 100 HRK |
Чехия | 500 Крон |
Дания | 350 DDK |
Финляндия | 25 Евро |
Франция | 30 Евро |
Германия | 25 Евро |
Гонконг | 1000 гонконгских долларов |
Ирландия | 30 евро |
Италия | 25 евро |
Новая Зеландия | 80 новозеландских долларов |
Норвегия | 200 норвежских крон |
Польша | 50 злотых |
Россия | 1000 руб. |
Сингапур | 100 SGD |
Словакия | 20 евро |
Испания | 20 евро |
Швеция | 200 SEC |
Швейцария | 40 CHF |
Тайвань | 3000 TWD |
Украина | 100 грн |
Объединенные Арабские Эмираты | 300 AED |
Великобритания | 30 фунтов |
Соединенные Штаты | 50 долларов |
Немного о самих метках
Про алгоритм выбора Activity при сканировании метки можно почитать
. Вкратце можно сказать, что ОС выбирает Activity на основании содержимого метки. Для гарантированного запуска нашего Activity нужно воспользоваться
(Android Application Records), что обозначает просто запись названия пакета приложения на метку. С помощью данного способа можно было бы гарантированно запускать разблокировку, но у меня не было под рукой меток, которые поддерживают стандарт NDEF. Поэтому я идентифицирую их по уникальному
Нет простой возможности разблокировки
Опять же, по соображениям безопасности приложение на устройстве не может просто взять и разблокировать экран защищённый каким-либо методом (пароль, пин, паттерн и др.). На данный момент существует 2 стандартных решения, которые позволяют разблокировать экран:
- Класс KeyguardManager.KeyguardLock.
- Флаги окна FLAG_DISMISS_KEYGUARD и FLAG_SHOW_WHEN_LOCKED.
Пишем обходные пути
Так как Android API не предоставляет нам красивых решений для разблокировки, то придётся писать
костыли
обходные пути.
В итоге было написано базовое приложение реализующее 3 метода разблокировки. Решил назвать его NFC Unlocker (ссылки на Google Play и исходники в конце поста). Реализованные обходные пути могут быть не стабильны, но это и так понятно исходя из их названия.
После чтения метки ОС должна запустить наиболее подходящее Activity. Поэтому воспользоваться BroadcastReceiver’ом не получится. Далее я опишу эти методы.
Плюсы:
- метка NFC, как и отпечаток пальцев, как и например MAC-адрес вашего роутера в своём роде уникальна. Можно вшить в несколько меток «одинаковый ключ», но метки всё-равно будут отличимы и программа-анализатор поймёт, что перед ней метка А и метка Б — просто с одинаковым содержимым;
- меткам не нужен источник питания — брелок, наклейка, браслет или кольцо «вечны«;
- они доступны — есть несколько форм-факторов (у меня например весь дом обклеен NFC-метками от Samsung / по размеру и внешнему виду они не больше-толще, чем наклейка из под жевательной резинки), есть чипы специально разработанные для того, чтобы вшивать их под одежду и т.п.
- низкая стоимость — набор NFC наклеек из 8-ми штук от компании Samsung обошёлся мне всего в 350 рублей (рынок огромен, есть китайские магазины — я даже не удивлюсь, если где-то их можно набрать «оптом» вообще за сущие копейки).
Сделаем свою реализацию
Самым идеальным вариантом для меня была интеграция со стандартным экраном блокировки. Хотелось, чтобы можно было прямо из него сканировать метки и авторизоваться, а если метки нет, то можно было бы использовать пароль как резервный вариант.
Перед тем как начать делать свою реализацию я определил две причины, по которым автор NFCSecure сделал своё приложение именно так, как оно работает сейчас, а не как задумал я. Опишем эти проблемы и пути их решения в разработанном мною приложении.
Сканер меток работает не всегда
А точнее он не работает как минимум в двух случаях, которые нас интересуют:
- Когда экран выключен.
- Когда мы находимся на экране блокировки.
Я предполагаю, что в этих случаях сканер не работает по соображениям безопасности. После сканирования метки запускается наиболее подходящее приложение, и неизвестно что это приложение захочет сделать. Для примера, Google Wallet (судя по видео) требует пин-код и выбор карты перед тем как приложить устройство к терминалу.
Правила работы сканера находятся в системном приложении NfcNci.apk. Там то и находится константа которая определяет в каком состоянии должен быть девайс, чтобы работало сканирование (можно почитать здесь). Естественно эту константу нужно изменить.
Многие разработчики выкладывают на xda-developers уже готовые модифицированные файлы NfcNci.apk под нужный вам девайс, поэтому я просто взял готовый файл и заменил им приложение на моём устройстве.Константе можно установить как минимум одно из двух значений, которые позволят сканеру считывать метки при заблокированном экране:
- Сканер работает при выключенном экране.
- Сканер работает при включенном экране и даже с активной блокировкой.
Первое решение
Конечно данное решение резко уменьшает порог вхождения обычных пользователей, так как теперь потребуется рутованный девайс и некоторые телодвижения, чтобы заменить оригинальное приложение. Но так как приложение не ориентированно на большие массы, то с этим можно смириться.
Установка флага для окна activity
И всё-таки флаг нам может помочь в реализации задуманного. Данное решение наиболее чистое, так как не требует рута и использует флаги окна, которые вполне себе разрешены. Для того, чтобы флаги сработали придётся очистить пароль методом DevicePolicyManager.
Алгоритм разблокировки таков:
- Пользователь сканирует метку, запускается наше Activity.
- Чистим пароль:
((DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE)).resetPassword("", 0);
- Ставим флаг окну нашего Activity:
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
- Завершаем Activity в методе onAttachedToWindow, так как именно в нём к окну уже применён наш флаг.
- В методе onDestroy восстанавливаем пароль пользователя.
Флаги окна
Флаги нужно устанавливать на родительское окно Activity. FLAG_DISMISS_KEYGUARD разблокирует экран только в том случае, если он не защищён. После закрытия окна блокировщик не будет восстанавливаться пока не выключится экран. FLAG_SHOW_WHEN_LOCKED лишь спрячет блокировщик (даже защищённый) и после закрытия окна он сразу же перейдёт на передний план.
То есть, опять же, эти флаги не смогут разблокировать защищённый экран. Максимум что можно сделать — показать своё окно поверх него.
В данном случае, чем меньше давать возможностей разработчику, тем больше повышается безопасность самой ОС. Возможности флагов, особенно FLAG_SHOW_WHEN_LOCKED, позволяют отображать своё приложение поверх блокировщика не нарушая безопасности системы. Но, к сожалению, нас это не устраивает.