Служба специальных возможностей Android - обновления экрана не соответствуют
У меня андроид AccessibilityService
развернут на Samsung Note 4 под управлением Android 5.0.1.
Я использую WhatsApp в качестве тестового стенда, но это относится к любому Приложению и больше относится к тому, как Служба специальных возможностей запускает события.
Событие 2048 (TYPE_WINDOW_CONTENT_CHANGED)
не соответствует уволен Android. Если я отправляю сообщения в мой WhatsApp с фокусом на экране и в 75% случаев это событие запускается, а иногда просто нет.
Для этого есть причина? События доступности не являются зависимыми..?
Кроме того, кажется, что событие 4096 (TYPE_VIEW_SCROLLED)
срабатывает ли постоянно, когда пользователь прокручивает или когда в окне чата WhatsApps появляется новая корреспонденция, кажется, нет никакого способа определить текущую позицию прокрутки устройства? AccessibilityEvent.getSource()
обеспечивает доступ к некоторым метаданным для списка (в данном случае android: id / list), однако информация о позиции прокрутки этого списка или его дочерних элементов отсутствует. Список дочерних элементов относится к тому, что отображается на экране и boundsToScreen/Parent
значения одинаковы, независимо от того, смотрите ли вы внизу списка, в середине или сверху. Есть ли какие-либо подсказки, чтобы помочь мне определить положение прокрутки от AccessibilityEventNodeInfo
экземпляр мне представлен?
Наконец, когда 2048 (TYPE_WINDOW_CONTENT_CHANGED)
событие срабатывает, бывают случаи, когда новые элементы фактически не доступны из AccessibiltyEvent.getSource()
(даже когда вы перебираете до корневого элемента vi цикл while, используя getParent()
и затем снова отсканируйте) Похоже, что событие делает снимок экрана до того, как изменение было применено к пользовательскому интерфейсу. thread.sleep
не помогает - как оказалось AccessibilityEventNodeInfo
это больше снимок, чем живой доступ к интерфейсу? Есть ли способ обойти это?
1 ответ
Для этого есть причина? События доступности не являются зависимыми..?
Я считаю более вероятным, что вы неправильно понимаете, когда TYPE_WINDOW_CONTENT_CHANGED
событие происходит, чем если оно не запущено или не поймано последовательно. Например, это конкретное событие не запускается при обновлении экрана, а только для нового содержимого окна. Разработчик приложения может вместо запуска нового действия выбрать перерисовку контента поверх своего действия. В этом случае, с точки зрения пользователя, содержимое окна изменилось, однако в бэкэнде приложения все, что произошло, - это нарисованы новые виды.
Thread.sleep не помогает - так как кажется, AccessibilityEventNodeInfo - это скорее снимок, чем прямой доступ к пользовательскому интерфейсу? Есть ли способ обойти это?
Это также объясняет, почему элементы отсутствуют в источнике событий. Вы получаете событие до отрисовки динамических элементов. Итак, запускается новый Activity и инициализируется новым контентом, однако приложение, вероятно, переходит в режим ожидания для некоторых типов сетевых /REST-ресурсов. До того, как эти ресурсы появятся, событие будет запущено, а вскоре после этого будет получен новый контент. Итак, вам кажется, что вы получаете неполный контент, но на самом деле вы получаете полный контент на момент запуска события. Вы метод thread.sleep работает просто отлично. Однако после того, как вы спите, вы не можете проверить значение event.getSource(), спящий не изменит то, что было передано этой функции. Вместо этого вы хотите спать, а затем пролистать всю иерархию представлений, чтобы найти нужную вам информацию. Спать, а затем использовать
getRootInActiveWindow();
на месте
event.getSource();
Есть ли какие-либо подсказки, чтобы помочь мне определить положение прокрутки из экземпляра AccessibilityEventNodeInfo, который мне представлен?
И да и нет. Нет, из службы специальных возможностей невозможно определить местоположение полосы прокрутки. Однако вы можете определить приблизительное положение события прокрутки, выполнив следующие действия:
private float getScrollPosition(AccessibilityEvent event) {
final AccessibilityRecordCompat record = new AccessibilityRecordCompat(event);
final int itemCount = event.getItemCount();
final int fromIndex = event.getFromIndex();
// First, attempt to use (fromIndex / itemCount).
if ((fromIndex >= 0) && (itemCount > 0)) {
return (fromIndex / (float) itemCount);
}
final int scrollY = record.getScrollY();
final int maxScrollY = record.getMaxScrollY();
// Next, attempt to use (scrollY / maxScrollY). This will fail if the
// getMaxScrollX() method is not available.
if ((scrollY >= 0) && (maxScrollY > 0)) {
return (scrollY / (float) maxScrollY);
}
// Finally, attempt to use (scrollY / itemCount).
// TODO(alanv): Hack from previous versions -- is it still needed?
if ((scrollY >= 0) && (itemCount > 0) && (scrollY <= itemCount)) {
return (scrollY / (float) itemCount);
}
return 0.5f;
}
Это прямо из кода Google TalkBack. Вы можете найти его в ScrollFormatter.java в проекте EyesFree. Это не идеальное решение. Если событие происходит из большого макета (как это часто бывает с веб-страницами в Chrome), вы можете получить тот же результат для большой части прокрутки. Тем не менее, API не поддерживают ничего более точного, чем этот, так что это необходимый хак, если вы хотите знать приблизительное местоположение прокрутки. Я думаю, что этот метод может быть значительно улучшен, даже с доступными API, хотя это потребует некоторой работы.