Как стать автором
Обновить

Комментарии 20

Во-первых, чтобы приложение считалось системным, его вовсе не обязательно подписывать сертификатом создателя системы. Достаточно просто залить apk-файл в папку /system/app. Для этого нужен либо рут, либо разблокированный загрузчик. Обновлять можно как обычно, оно будет ставиться в /data/app, но всё равно иметь полный доступ к системе. Главное — чтобы подписи совпадали.
Во-вторых, на планшетах доступен многопользовательский режим. С недавнего времени (4.3, кажется) пользователям можно ставить ограничения — т.е. выбирать, в какие приложения они могут заходить, а в какие — нет. Идея в том, чтобы создать пользователя с нужными ограничениями (отключить ему настройки и браузер, например), а на админа поставить пароль. Приложение киоска разумно поставить в качестве лаунчера — таким образом уже можно перехватить кнопки back и home, а recents ничего страшного всё равно не сделает, потому что кроме лаунчера никаких приложений будет не запустить, а сам лаунчер там не показывается.
Помню, перемещал приложение какой-то утилитой типа System app mover но SecurityException было все равно. Наверное недостаточно пытался.

А вот с многопользовательским режимом вариант интересный, спасибо. Надо попробовать.
Попробовал ограниченные профили в многопользовательском режиме. На Nexus 7 (2012) при входе в профиль в списке приложений помимо моего, доступ к которому я разрешил, почему-то есть еще Downloads, Часы, Настройки и Play маркет. Причем маркет при запуске сказал что его запускать запрещено, а часы и настройки запустились и позволили настройки менять как угодно. В настройках профиля отключить их было нельзя (а специально я не включал).

Да и работает визуально все как-то медленнее, чем из под обычного профиля, как будто в виртуальной машине. Видимо, Google еще не до конца доделали эту штуку.
много раз слышал про приложения, которые требуют ввести пароль для запуска определённой программы. В основном — чтобы не дать друзьям доступ к сообщениям, галерее, телефонной книге и т. д. Думаю, возможно такую программу использовать для блокирования доступа в Настройки и в Часы. Вот например: play.google.com/store/apps/details?id=com.sp.protector.free
Про кастомный home я написал в п.3. Это не дает особо функциональности киоска, т.к. настройки и системные кнопки это не часть лаунчера, все равно остается куча вопросов
А я вот про кастомный локскрин подумал. Там точно нет доступа ни к настройкам ни к меню.
Как оно без рута, заработает ли — мне неведомо…
Нет официального апи для создания своих лок скринов. Всё, что видел без root, работало как написано в пункте 4.
А, кстати, есть ещё разрешение «показывать интерфейс поверх других приложений» — можно попробовать сделать что-нибудь интересное с его помощью, например, включить immersive mode, а потом создать прозрачное окно поверх всего и перехватывать им жесты открытия навигации.
Также интересовал этот вопрос. Вот обсуждение
stackoverflow.com/questions/17549478/how-to-disable-home-and-other-system-buttons-in-android

после того как один из участников добавил призовую карму, более-менее внятные пути решения сразу нашлись (без этих «блокировать экран неправильно и невозможно»)
Не первый год уже существует сеть кафе в которых для заказа используются дешевые Android планшеты и там эта проблема решена, на каждый чих требуют ввести пароль. Максимум можно посмотреть недавние и список приложений, на всё остальное требуется пароль.
Я по осени сделал веб-браузер для меню в онлайне на дешевых планшетах за 2500 рублей с Android 4.0.4 — проблем никаких нет в работе.
Админский доступ получается нажатием определенной комбинации хардварных клавиш.
Планшеты рутованы, конечно.
Какие способы киоск-защиты применяли, если не секрет?
Честно скажу — в Android и Java не специалист. Делал, потому что очень попросили.
Во-первых — приложение работает как будто бы оно лаунчер:

    < activity android:name="..."
            android:label="..."
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
            android:launchMode="singleInstance"
            android:stateNotNeeded="true"
            android:configChanges="orientation|keyboardHidden">
            < intent-filter>
                < action android:name="android.intent.action.MAIN" />
                < category android:name="android.intent.category.HOME" />
                < category android:name="android.intent.category.DEFAULT" />
                < category android:name="android.intent.category.LAUNCHER" />
            < /intent-filter>
        < /activity>'


Во-вторых, прибиваю системный процесс или наоборот включаю, когда надо:
    public void BlockSystemUI (boolean block) {
        if(block) {
            // block
            try{
                //REQUIRES ROOT
                Build.VERSION_CODES vc = new Build.VERSION_CODES();
                Build.VERSION vr = new Build.VERSION();
                String ProcID = "79"; //HONEYCOMB AND OLDER

                //v.RELEASE  //4.0.3=
                if(vr.SDK_INT >= vc.ICE_CREAM_SANDWICH){
                    ProcID = "42"; //ICS AND NEWER
                    Log.i("XXXX Log", "ICS");
                } else {
                    Log.i("XXXX Log", "HONEYCOMB");
                }

                //REQUIRES ROOT
                Process proc = Runtime.getRuntime().exec(
                        new String[]{"su","-c","service call activity "+ ProcID +" s16 com.android.systemui"}
                );
                proc.waitFor();
            } catch(Exception ex) {
                Toast.makeText(getApplicationContext(), ex.getMessage(), Toast.LENGTH_LONG).show();
                Log.i("XXXX Log", "EXCEPTION");
            } finally {
                Log.i("XXXX Log", "FINALLY");
            }
        } else {
            // unblock
            try {
                Runtime.getRuntime().exec(
                        new String[]{"am","startservice","-n", "com.android.systemui/.SystemUIService"});
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    private boolean isSystemUIServiceRunning() {
        ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (service.service.getClassName().contains("com.android.systemui")) {
                Log.i("XXXX Log", "System UI is running");
                return true;
            }
        }
        Log.i("XXXX Log", "System UI is NOT running");
        return false;
    }
По своему опыту могу сказать что кроме необходимости запретить пользователю влазить в какие либо настройки или закрывать приложение, есть еще необходимость в автоматическом обновлении. Вначале разработки я надеялся что можно обойтись без рута, но в итоге пришел к выводу что без рута полноценное kiosk-приложение не получится.
Учитывая что устройства одинаковые, то получение рута не такая уж и проблема. Клиент не может купить, например, какой то планшет и поставить на него наше приложение, т.е. по факту мы выбираем устройство.
Я так же переписывался с одним разработчиком, тоже занимающимся kioskMode приложениями (кстати там есть толковые статьи по этому вопросу). Так вот они разрабатывали kiosk-приложение для такси (я так понял в Индии), в каждое такси вставлялся какой то китайский планшет и пассажиры могли что то там делать с их приложением. Опять таки учитывая что устройства везде одинаковое, они получали рут на каждом планшете и спокойно могли делать все что хотели. Только в их случае они для заказчика сделали скрипт, который получает рут на планшете, чтобы он сам мог без участия разработчиков устанавливать новые планшеты.
Так что я склоняюсь к такому подходу. Если же устройств много и пользователи сами могут установить себе приложение, тогда такой вариант не пройдет конечно.
А что, если подойти к решению задачи с другой стороны? То есть ограничивать запуск вообще всех других приложений, кроме выбранного. Доступ давать только через пин или пароль.

Сам лично пользуюсь этим, доволен (к разработчикам приложения отношения не имею) — play.google.com/store/apps/details?id=com.campmobile.android.kidstimer

Глянул на SO, предлагают подобное решение.

Насколько быстро получится сваять аналог?

Но надеюсь в итоге Гугл озадачится выпуском Kiosk API.
В целом, достаточно получить системные права, положив приложение в системную папку. При этом у нас появляется доступ к permissions c protection level = system_or_signature, и одно из самых полезных разрешений — CHANGE_COMPONENT_ENABLED_STATE, позволяющее налету включать/выключать системные и пользовательские приложения. При этом отключенные приложения затруднительно (если вообще возможно) включить обратно в стандартных настройках. Таким образом можно отключить другие лончеры (конечно, сделав им своё приложение), можно отключить даже пакет com.android.systemui (который отвечает за статус-бар, список недавних приложений и некоторые другие компоненты системы).
Мне кажется, это очень хорошо, что андроид не позволяет любому пользовательскому приложению получить такой уровень доступа, иначе кроме обычных зловредов, мы бы ещё получили тонны локеров на андроиде, по типу виндовых (заплати деньги, чтобы получить доступ к данным и рабочему столу).
Разные производители могут иметь свои возможности, например, у самсунга в системе есть свои API для киоска, блокировки приложений и корпоративных политик. Просто там туда доступ не получить. Возможно, эти возможности также используются на витринных аппаратах, которые гоняют ролики.
В чистом андроиде есть поддержка администрирования устройств, но там весьма слабые возможности, в основном для корпоративных политик, связанных с безопасностью (блокировка экрана, надёжность паролей, шифрование данных, отключение камеры и полная очистка устройства).
В прошлом году был на стенде Samsung, там были планшетники в типа киоск режиме. Железные кнопки отключены не были. По крайней мере организаторы стенда никакие хитрые API для киоска не использовали. Был разочарован.

Если киоск, то либо iOS, либо рутовать и «хачить», приличных вариантов нет.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории