Получение имени макета действия с использованием службы специальных возможностей в Android

Я пытаюсь создать приложение, чтобы получить имя пакета, имя действия и имя макета действия (XML) других приложений. Для этой цели я использую службу специальных возможностей, чтобы получить WINDOW_STATE_CHANGED окна переднего плана.

Чего я достиг?

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

Чего я не могу достичь!

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

Что я уже пробовал:

ШАГ 1:

Создан файл accessibilityservice.xml в папке res/xml, как показано ниже.

<accessibility-service
    xmlns:tools="http://schemas.android.com/tools"
    android:accessibilityEventTypes="typeWindowStateChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagIncludeNotImportantViews"
    android:canRetrieveWindowContent="true"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:ignore="UnusedAttribute"/>

ШАГ 2:

Создан класс службы WindowChangeDetectingService.java и зарегистрированы имя пакета и активность, как показано ниже.

    import android.accessibilityservice.AccessibilityService;
    import android.accessibilityservice.AccessibilityServiceInfo;
    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.pm.ActivityInfo;
    import android.content.pm.PackageManager;
    import android.os.Build;
    import android.util.Log;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.accessibility.AccessibilityEvent;
    import android.view.accessibility.AccessibilityNodeInfo;

    import java.util.List;

    public class WindowChangeDetectingService extends AccessibilityService {

        @Override
        protected void onServiceConnected() {
            super.onServiceConnected();

            //Configure these here for compatibility with API 13 and below.
            AccessibilityServiceInfo config = new AccessibilityServiceInfo();
            config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
            config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;

            if (Build.VERSION.SDK_INT >= 16)
                //Just in case this helps
                config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;

            setServiceInfo(config);
        }

        @Override
        public void onAccessibilityEvent(AccessibilityEvent event) {

            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
                if (event.getPackageName() != null && event.getClassName() != null) {
                    ComponentName componentName = new ComponentName(
                        event.getPackageName().toString(),
                        event.getClassName().toString()

                    );


                    Log.i("AccessPackagename",  event.getPackageName().toString());
                    Log.i("AccessgetClassName",  event.getClassName().toString());

                }
            }
        }
}

ШАГ 3: Зарегистрированная служба WindowChangeDetectingService, созданная в файле manifest.xml, как показано ниже.

<service
            android:name=".WindowChangeDetectingService"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService"/>
            </intent-filter>
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibilityservice"/>
        </service>

ВЫВОД: (получено из Logcat)

08-18 12:51:45.430 11206-11206/com.takeoffandroid.screenlog I/AccessPackagename: com.takeoffandroid.screenlog
08-18 12:51:45.430 11206-11206/com.takeoffandroid.screenlog I/AccessgetClassName: com.takeoffandroid.screenlog.MainActivity

Мое требование: (ожидаемый результат)

08-18 12:51:45.430 11206-11206/com.takeoffandroid.screenlog I/AccessPackagename: com.takeoffandroid.screenlog
    08-18 12:51:45.430 11206-11206/com.takeoffandroid.screenlog I/AccessgetClassName: com.takeoffandroid.screenlog.MainActivity

--------------------------------------------------------------------    --------------------------------------------------------------------

    08-18 12:51:45.430 11206-11206/com.takeoffandroid.screenlog I/AccessgetLayoutName: activity_main.xml //Should be capable to read the layout name of the MainActivity

--------------------------------------------------------------------   --------------------------------------------------------------------

Я работаю над этим требованием последние два дня, но не могу найти какой-либо метод или способы сделать это в Android с помощью службы специальных возможностей. Любая помощь или предложения будут очень полезны для меня. Заранее спасибо.


person Chandru    schedule 18.08.2017    source источник


Ответы (1)


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

<accessibility-service
xmlns:tools="http://schemas.android.com/tools"
android:accessibilityEventTypes="typeWindowStateChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagReportViewIds|flagIncludeNotImportantViews"
android:canRetrieveWindowContent="true"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:ignore="UnusedAttribute"/>

Важное изменение здесь заключается в следующем:

android:accessibilityFlags="flagReportViewIds|flagIncludeNotImportantViews"

или даже более конкретно эту часть:

флагReportViewIds

Кроме того, вы не должны включать свою функцию onServiceConnected. Вы изменяете всю конфигурацию, которую вы делаете в своем XML-файле service_config. Вы тоже не совсем правильно делаете. Создание новой служебной информации опасно, так как вы вряд ли заполните все важные поля. Эта строка:

AccessibilityServiceInfo config = new AccessibilityServiceInfo();

Должно быть так:

AccessibilityServiceInfo config = getServiceInfo()

А затем изменить это! Хотя, если серьезно, не делайте этого, просто полагайтесь на XML-реквизиты service_config.

Как только у вас будет правильная конфигурация, вы сможете сделать это:

someAccessibilityNodeInfo.getViewIdResourceName()

Какой идентификатор вы ищете.

person ChrisCM    schedule 20.08.2017
comment
Большое спасибо за ваш ответ. Я не могу получить метод getViewIdResourceName из AccessibilityServiceInfo. Я пытался использовать getRootInActiveWindow().getViewIdResourceName(), но выдавал NullPointerException - person Chandru; 21.08.2017
comment
java.lang.NullPointerException: попытка вызвать виртуальный метод 'java.lang.String android.view.accessibility.AccessibilityNodeInfo.getViewIdResourceName()' для ссылки на нулевой объект - person Chandru; 21.08.2017
comment
Если это так, вы неправильно выполнили часть настройки ИЛИ представление не имеет имени ресурса. Не все представления делают. На самом деле корневого просмотра никогда не будет. Корневое представление — это принадлежащий ОС Android контейнер для вашей деятельности. Корень вашей деятельности находится немного ниже по иерархии. - person ChrisCM; 21.08.2017