Мне нужно выяснить, когда было последнее взаимодействие с пользователем, независимо от того, какое приложение находится сверху. Меня не волнует, где и что такое событие, я просто должен знать, когда это было. Или, как вариант, я получаю событие.
Я пробовал несколько вещей:
getevent
works (новая строка приходит каждый раз при получении касания), однако вам нужен root, и поэтому это не подходит для меня.Также обратите внимание: это не касается безопасности, поскольку мне не нужна какая-либо идентифицирующая информация, такая как местоположение касания. Просто штамп типа (или живое событие).
Я открыт для использования отражения, чтобы понять это.
@user2558882 имеет очень хорошее решение. На данный момент это лучший подход, с которым я столкнулся.
В то время как это здорово, все равно требуется, чтобы пользователь вручную включил наше приложение в элементы управления доступности. У нас есть клиенты с тысячами устройств, и у нас есть способ автоматически обновлять и изменять настройки. Мы стараемся, чтобы ручная настройка была минимальной, но некоторые вещи по-прежнему требуют ввода пользователя, например, включения режима Device Admin. Таким образом, это решение приемлемо, но я все еще открыт для того, чтобы не требовать ввода пользователем.
В результате я использовал идею @user2558882 для использования службы доступности. Хотя другие идеи приветствуются.
Это просто идея и не может быть полностью переносимой.
Вот что может сделать AccessibilityService:
Служба доступности работает в фоновом режиме и принимает обратные вызовы когда система AccessibilityEvents запущена. Такие события обозначают некоторый переход состояния в пользовательский интерфейс, например, фокус изменилось, нажата кнопка и т.д.
Вы узнаете о событии внутри onAccessibilityEvent(AccessibilityEvent)
:
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
// Some event
timeSinceLastInteraction = System.currentTimeMillis();
}
Вы можете периодически регистрировать обновления:
Log.i("LOG_TIME_ELAPSED", "Last user interaction was " +
((System.currentTimeMillis() - timeSinceLastInteraction) / 1000) +
" seconds ago.");
Существует два способа настройки службы AccessibilityService:
В коде внутри onServiceConnected(). (API 4 и далее)
В xml, используя тэг meta-data
в вашей службе. (API 14 и далее)
В вашем приложении, возможно, вы можете установить AccessibilityServiceInfo.eventTypes
в:
accessibilitySeviceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
Но TYPES_ALL_MASK будет включать в себя такие уведомления, как AccessibilityEvent.TYPE_ANNOUNCEMENT, AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED и т.д., которые, как я полагаю, вы не хотите перехватывать. Итак, вам нужно выбрать подмножество AccessibilityEvent.TYPE_X.
Еще одна вещь, о которой вы должны быть осторожны, - это тайм-аут уведомления:
Тайм-аут после последнего события данного типа перед AccessibilityService уведомляется.
Тайм-аут уведомления о событиях полезен для предотвращения распространения событий для клиента слишком часто, так как это достигается с помощью дорогой межпроцессный вызов. Можно подумать о тайм-ауте как о критерии для определения того, когда сформировалось событие.
Итак, будьте великодушны со значением тайм-аута.
Вы найдете эту страницу очень полезной, если вы решите пойти с опцией AccessibilityService: Разработка службы специальных возможностей.
Из ваших комментариев на ответ Chloe кажется, что устройство находится под вашим контролем: это означает, что в какой-то степени вам не нужно полагаться на пользователя для включения службы:
Жизненный цикл службы доступности управляется исключительно системы и следует установленному сроку службы. Кроме того, запуск или остановка службы доступности инициируется исключительно явным действием пользователя посредством включения или отключив его в настройках устройства.
Вы можете включить AccessibilityService во время развертывания и, возможно, ограничить доступ к меню настроек с помощью приложения, такого как AppLock.
Еще одна опция - проверять, включен ли ваш AccessibilityService время:
AccessibilityManager am = (AccessibilityManager)
getSystemService(ACCESSIBILITY_SERVICE);
List<AccessibilityServiceInfo> listOfServices =
am.getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
for (AccessibilityServiceInfo asi : listOfServices) {
// Check if your AccessibilityService is running
}
Если функция AccessibilityService была отключена любознательным/пресловутым пользователем, вы можете заблокировать устройство, отображая полноэкранное представление с текстом: Device has been locked. Contact a Sales Rep to unlock this device
.
Я считаю, что вам нужно вернуть false, чтобы указать, что ваше прозрачное служебное окно не потребляет событие касания. Таким образом, цикл событий передаст его вниз по стеку в нижние окна.
https://developer.android.com/reference/android/view/View.OnTouchListener.html
Другая возможность - это добавить службу, которая слушает события движения/акселерометра.
https://developer.android.com/guide/topics/sensors/sensors_motion.html
Другая возможность - прослушать ACTION_USER_PRESENT
https://developer.android.com/reference/android/content/Intent.html#ACTION_USER_PRESENT
или ACTION_SCREEN_ON
https://developer.android.com/reference/android/content/Intent.html#ACTION_SCREEN_ON
AccessibilityService
.