Привет, Хабр! Меня зовут Светлана Палицына, я — Android-разработчик в мобильной команде «Лаборатории Касперского», где мы создаем решения для защиты мобильных устройств.

Мои коллеги из Kaspersky уже рассказывали о наборе решений и технологий для управления поведением устройств, известном как Mobile device management (про ее применение в iOS можно прочитать здесь, а про использование в Android — здесь). Я же подробно рассмотрю один из режимов этого механизма — Lock task mode, также известный как Kiosk-режим.



Статья будет полезна Android-разработчикам, которые хотят дать своим пользователям возможность работы их устройств в режиме одного или нескольких приложений и пополнить копилку знаний информацией о возможностях MDM.

Общие сведения


Для начала давайте разберемся, что же такое Lock task mode-режим, для чего он нужен и какие задачи позволяет решить.

Итак, часто компаниям приходится искать решения не только для мониторинга состояния мобильного устройства, но и для ограничения какой-то из предоставляемой устройством функциональности. Распространенный сценарий для компаний, сотрудники которых используют в своей деятельности смартфоны и планшеты: устройству требуется задать поведение, при котором пользователю будет доступно для взаимодействия только одно или несколько приложений, без возможности переключиться на другие приложения, выйти на хоум-скрин или даже открыть верхнюю шторку управления.

Эту задачу можно решить с помощью так называемого режима Lock task mode (официального перевода на русский не встречала, но примерно можно перевести как режим блокировки приложения/задачи), который как раз предоставляет возможность зафиксировать на экране устройства одно приложение или же обеспечить переключение только между «разрешенными», то есть заранее сконфигурированными и установленными приложениями. При этом только приложения, которые были выбраны администратором как доступные, могут быть запущены пользователем на устройстве. Доступ же к другим приложениям запрещен.

Как уже было упомянуто выше, условно можно выделить два режима функционирования у фичи Lock task mode: так называемые Single app mode и Multi app mode. Первый, Single app mode, предполагает доступность только одного разрешенного для взаимодействия приложения. Иногда также встречается и другое название этого режима — kiosk. Режим Multi app mode, соответственно, означает, что пользователю может быть доступно более одного приложения.

Также режим Lock task mode позволяет настроить поведение системных функций, то есть появляется возможность контролировать поведение следующих элементов, предоставляемых ОС:
  • кнопка доступа к недавним приложениям;
  • кнопка выхода на домашний экран;
  • кнопка питания устройства (можно выставить запрет реакции на долгое нажатие на кнопку включения/выключения, что затруднит для пользователя возможность выключить устройство);
  • уведомления (то есть можно разрешить или запретить показ всплывающих уведомлений и соответствующих иконок в статус-баре смартфона);
  • статус-бар (а именно отображение системной информации в нем, такой как уровень заряда батареи, мощность сигнала и так далее);
  • экранная блокировка (то есть можно разрешить или запретить использовать различные методы блокировки экрана, такие как PIN, пароль и так далее).

Таким образом, пользователь может свободно работать в «главном» выбранном приложении, но не может изменять параметры телефона или пользоваться им по какому-либо другому назначению, так как доступ к другим приложениям и системным функциям невозможен.

В подавляющем большинстве случаев функциональность киоск-режима требуется именно компаниям (а не конечным пользователям) для обеспечения контроля и управления устройствами, предназначенными для строго определенной цели, так называемыми dedicated devices (в прошлом также известных как company owned single use devices, COSU). Dedicated devices — это полностью управляемые устройства, которые служат строго заданной цели, представляя собой, таким образом, терминал для выполнения конкретно поставленной задачи. В большинстве случаев эти устройства должны предоставлять определенный функционал одной из двух категорий пользователей:
  1. Сотрудники компании. Такой подход помогает сфокусировать внимание сотрудника только на решаемой задаче. Примером могут служить ситуации, когда сотрудникам выдаются устройства с установленными вспомогательными приложениями для достижения конкретных целей(не ограничиваясь приведенными примерами):
    • проведение инвентаризации;
    • оформление заявок;
    • координация работы транспорта;
    • другие специализированные задачи.

  2. Клиенты компании. В этом случае человек получает максимально простой интерфейс (правильнее будет сказать, не усложненный дополнительными опциями системы, а сфокусированный именно на узконаправленном приложении или наборе приложений), заточенный под конкретный сценарий. Это может быть:
    • приложение, выступающее в роли цифровой вывески компании;
    • приложение, установленное на планшете в демонстрационном стенде;
    • приложение, управляющее работой вендингового автомата;
    • приложение для формирования очереди и регистрации на различные услуги;
    • приложение для ресторанов, позволяющее сделать заказ с устройства без помощи официанта;
    • приложение для терминала в аэропорту или гостинице для check-in;
    • другие приложения для множества разных услуг.


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

Есть один нюанс, который надо учитывать: поскольку специфика использования Lock task mode предполагает, что устройство является специализированным (тот самый Dedicated device, о котором мы говорили выше), то только приложение, являющееся приложением Device Policy Controller (DPC), может устанавливать список разрешенных приложений и таким образом конфигурировать Lock task mode. Приложение Device Policy Controller — это приложение, которое может задавать локальные политики устройства. Такими политиками может быть доступ к функциональности устройства, например камере или Bluetooth, или ограничение возможных действий пользователя, например запрет на изменение громкости или запрет на изменение Wi-Fi-конфигурации, и так далее. Следует подчеркнуть, что API, который используется для Lock Task Mode, доступен для приложений, имеющих права Device Owner (DO) или Profile Owner (PO, Work Profile).

Иными словами, в зависимости от конкретной цели и реализации, для запуска приложения в режиме Lock task mode либо приложение должно быть запущено внешним приложением Device Policy Controller, установленным на устройстве, либо это приложение само должно выступать в качестве Device Policy Controller и самостоятельно контролировать свою работу в этом режиме (стартовать и останавливать работу режима, задавать список доступных приложений и так далее).

Какой API от Google позволяет реализовывать режим Lock task mode


Теперь, когда у нас есть понимание, что представляет собой Lock task mode и для чего он нужен, давайте подробнее рассмотрим API, который позволяет реализовать нужное нам поведение.

Для начала, в качестве небольшого отступления в рамках подготовки к обзору используемых методов, скажу пару слов про класс DevicePolicyManager, который предоставляет этот API. Этот класс предоставляет методы для управления политиками, заданными на устройстве. Чтобы использовать эти методы, приложение должно быть зарегистрированным как администратор устройства и зачастую, как в случае API для Lock Task Mode, иметь права Device Owner или Profile Owner. Более подробно про запрос прав администратора устройства, а также механизмы DO и PO можно прочитать в статье моей коллеги Марии Глущенко.

Большинство методов этого класса требуют в качестве параметра объект класса ComponentName — это идентификатор компонента приложения с правами администратора, содержащий информацию о пэкадже приложения и имени класса.

В случае если приложение не является администратором, не имеет прав Device Owner или Profile Owner, будет выброшено исключение SecurityException.

Также уточню, что сам режим Lock task mode может быть запущен на устройствах, работающих под управлением ОС Android, начиная с версии 5 и выше.

Итак, переходим ближе к делу, а точнее к конкретному API, с помощью которого мы можем задать нужные нам ограничения и добиться требуемого поведения. В рамках этого обзора также посмотрим, начиная с каких версий ОС доступны те или иные методы. Все методы и константы для удобства будут сразу сопровождаться ссылками на официальную документацию.

Начнем с начала :) Основная функциональность, на которой строится работа Lock task mode, базируется на возможности задать одно или несколько доступных приложений. Это может быть сделано с помощью метода DevicePolicyManager.setLockTaskPackages(), в параметры которого следует передать ComponentName и список, состоящий из строк с указанием package name приложений, которые должны быть доступны в рамках Lock Task mode. Если в дальнейшем потребуется получить список таких приложений (которые уже были ранее добавлены в «белый список»), можно воспользоваться методом DevicePolicyManager.getLockTaskPackages(), достаточно передать туда только ComponentName и получить в ответ список пэкаджей.

Пример:

// Allowlist two apps.
private val KIOSK_PACKAGE = "com.example.kiosk"
private val PLAYER_PACKAGE = "com.example.player"
private val APP_PACKAGES = arrayOf(KIOSK_PACKAGE, PLAYER_PACKAGE)

// ...

val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE)
        as DevicePolicyManager
val adminName = getComponentName(context)
dpm.setLockTaskPackages(adminName, APP_PACKAGES)

// ...

var listOfAllowedPackages = dpm.getLockTaskPackages(adminName)

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

Для версии Android ниже 9.0 каждое приложение может стартовать только свою activity в режиме Lock task. Для этого предполагается использовать метод Activity.startLockTask(). При этом надо учитывать, что в момент этого вызова активити должна быть на переднем плане, поэтому следует обращаться к этому методу, например, в колбэке Activity.onResume(). Также надо не забыть проверить, что требуемый packageName уже находится в списке разрешенных приложений режима Lock Task. Учитывая вышесказанное, на стороне приложения, которое должно быть запущено как kiosk-приложение, код по старту режима на устройствах Android до версии 9.0 будет выглядеть примерно так:

override fun onResume() {
    super.onResume()
    if (dpm.isLockTaskPermitted(context.packageName)) {
        activity.startLockTask()
    }
}

Для Android версии 9.0 и выше приложение, зарегистрированное как Device Admin и обладающее правами Device Owner или Profile Owner, может запускать в режиме Lock Task не только себя, но и другие приложения. При старте главной активити киоск-приложения требуется в метод Context.startActivity() передать соответствующий интент и объект с дополнительными опциями, содержащими информацию о том, как эта активити должна быть запущена. Можно получить указанный объект с опциями через метод ActivityOptions.makeBasic(), а после получения вызывать на нем метод ActivityOptions.setLockTaskEnabled() с параметром true.

Таким образом, для поддержки устройств Android и версий 5–9, и версий выше можно использовать пример кода ниже:


private fun startKioskActivity(intent: Intent?) {
	if (intent != null) {
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// Для версий Android выше 9.0 можем запускать сторонние приложения 
// в режиме Lock Task. Для этого получаем опции запуска, выставляем
// параметр LockTaskEnabled в true и стартуем интент
			val options = ActivityOptions.makeBasic()
			options.setLockTaskEnabled(true)
			context.startActivity(intent, options.toBundle())
		} else {
// Для версий Android от 5.0 до 9.0 только само приложение может
// запускать себя в режиме Lock Task, используя код из предыдущего
// примера. При этом из приложения с Device Owner правами следует
// запустить нужную activity
			context.startActivity(intent)
		}
	}
}

После того как мы задали список доступных приложений и запустили режим на устройстве, рассмотрим способ выйти из него в привычный режим. Приложениям с правами Device Owner или Profile Owner, начиная с версии ОС 6.0, достаточно удалить packageName из списка разрешенных приложений. Для этого нужно передать пустой массив в качестве параметра метода DevicePolicyManager.setLockTaskPackages().

val context = context
val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE)
        as DevicePolicyManager
dpm.setLockTaskPackages(emptyArray())

Для Android версий 5.0 и 5.1 удаление прежде разрешенного packageName методом, указанным выше, не приведет к остановке режима Lock Task, поэтому в таких случаях само приложение, которое призвано запускаться в режиме Kiosk, должно вызвать метод Activity.stopLockTask() в противовес ранее вызванному методу Activity.startLockTask(), рассмотренному выше.

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

По умолчанию, когда на устройстве включен режим Lock Task mode, система модифицирует пользовательский интерфейс так, чтобы исключить любую возможность пользователя выйти из приложения, таким образом максимально фокусируя его внимание именно на функциональной стороне самого приложения, которое выведено на экран и доступно для взаимодействия. Тем не менее, начиная с Android версии 9.0, разработчикам предоставляется возможность самостоятельно настроить эти параметры в соответствии со своими нуждами, для чего был добавлен метод DevicePolicyManager.setLockTaskFeatures(). Этот метод принимает обязательный параметр ComponentName и int-значение, которое является комбинацией флагов, отвечающих за ту или иную функциональность, которую можно включить или выключить. Если в качестве этого значения указать 0 (что также соответствует флагу LOCK_TASK_FEATURE_NONE), то все настраиваемые фичи будут выключены.

Если есть необходимость узнать, какая функциональность в режиме Lock Task уже была ограничена (то есть по сути получить int-значение — комбинацию флагов), можно вызвать метод DevicePolicyManager.getLockTaskFeatures(), куда следует передать только параметр ComponentName.

Ниже приведен список UI-фич и соответствующих флагов, доступных для конфигурации:

Функциональность и флаг


Описание


Системная кнопка Home


LOCK_TASK_FEATURE_HOME


Показывает или скрывает системную кнопку Home


Системная кнопка Recent apps


LOCK_TASK_FEATURE_OVERVIEW


Показывает или скрывает системную кнопку Recent apps, с помощью которой можно посмотреть список недавних открытых приложений. Этот флаг может быть использован только совместно с флагом LOCK_TASK_FEATURE_HOME, иначе при попытке установить этот флаг отдельно метод setLockTaskFeatures выбросит исключение IllegalArgumentException


Системный диалог питания


LOCK_TASK_FEATURE_GLOBAL_ACTIONS


Разрешает или запрещает показ диалога, возникающего при долгом нажатии на кнопку питания. По умолчанию только эта опция включена при запуске режима Lock task. Очевидно, что в случае включения этого флага у пользователя практически не останется способов выключить устройство


Уведомления в статус-баре


LOCK_TASK_FEATURE_NOTIFICATIONS


Разрешает или запрещает показ уведомлений (включая сами всплывающие уведомления и иконки в статус-баре) для всех приложений. Этот флаг может быть использован только совместно с флагом LOCK_TASK_FEATURE_HOME, иначе при попытке установить этот флаг отдельно метод setLockTaskFeatures выбросит исключение IllegalArgumentException


Системная информация в статус-баре


LOCK_TASK_FEATURE_SYSTEM_INFO


Разрешает или запрещает показ системной информации в статус-баре (информация о заряде батареи, вибрации, типе беспроводного соединения и так далее)


Системный экран блокировки


LOCK_TASK_FEATURE_KEYGUARD


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


Обобщающий флаг для всех указанных выше флагов


LOCK_TASK_FEATURE_NONE


Запрещает все указанные выше фичи



В качестве примера можно рассмотреть, как выглядит простейшее демоприложение с включенными и выключенными флагами. На первом скриншоте флаги включены, на втором выключены. Если сравнить два этих скриншота, то видно, что пропадает кнопка Home и Recent apps и пропадает информация из статус-бара.



Для еще большей настройки и кастомизации решения имеет смысл проштудировать и другие опции, которые доступны в режиме Device Owner, чтобы как можно более точно настроить устройство под конкретную цель. Список различных ограничений можно найти в классе UserManager, просмотрев доступные флаги ограничений. При работе с этим API рекомендую сразу обращать внимание на то, в какой версии было добавлено то или иное ограничение, чтобы понимать, на каких версиях операционной системы можно будет реализовать требуемое поведение.

Обычно любой флаг-ограничение этого класса может быть установлен и снят с помощью методов класса DevicePolicyManager: DevicePolicyManager.addUserRestriction() и DevicePolicyManager.clearUserRestriction ().

Пример:

private fun setRestrictionState(restriction: UserRestriction, enabled: Boolean) {
   if (enabled) {
       dpm.addUserRestriction(adminComponentName, restriction)
   } else {
       dpm.clearUserRestriction(adminComponentName, restriction)
   }
}

Заключение


В этой статье был рассмотрен режим Lock task mode, предоставляющий возможности работы устройства на базе операционной системы Android в режиме одного или нескольких выбранных приложений. Мы познакомились с возможными областями применения этого режима, рассмотрели его возможные дополнительные конфигурации и поближе пощупали сам API. Надеюсь, эта статья была вам полезна для ознакомления с режимом или при реализации данного режима для целей вашего приложения. Конечно, можно долго углубляться в тему, рассматривать дополнительные методы, corner cases, применимость для разных устройств — все сценарии и вопросы трудно охватить в одной статье, поэтому если у ас возникли дополнительные вопросы, предлагаю обсудить их в комментариях :)

Комментарии (2)


  1. segment
    10.08.2023 15:02

    Lock Task это не совсем режим kiosk. Ну то есть сделать такое приложение можно, но лучше воспользоваться EMM. Кстати, сталкивались ли с неотключаемыми всплывающими сообщениями? На планшетах samsung даже в режиме kiosk с полными правами и со всевозможными ограничениями в policy осталось у нас две проблемы: это всплывающее меню о том, что подключенная зарядка работает в медленном режиме; и при перезагрузке планшета иногда приложение не запускается самостоятельно (приходится через EMM API перезагружать устройство).


    1. SvetlanaPalitsyna Автор
      10.08.2023 15:02
      +1

      Добрый день)

      Почти любую задачу можно решить разными способами, и оценка "лучше/хуже" всегда исходит из конкретной ситуации) В этот раз был рассмотрен подход с Lock Task mode, но, конечно в разных ситуациях кому-то могут быть более удобны другие варианты.

      Касаемо проблем: встречали разные баги, но они были device specific, например, на одном телефоне Samsung (Android 10) не отключалась возможность зайти в Recent apps, но тот же код на другом телефоне отрабатывал как ожидалось. Поскольку тут дело за реализацией на уровне ОС, к сожалению, поправить это поведение особо не получится. Вероятно, описанные Вами проблемы того же рода.