Как AccessibilityService работает поверх других приложений?

Фон

Разрешение SAW (окно системного предупреждения) можно использовать для рисования контента поверх других приложений.

Мне очень давно сказали, что служба доступности тоже может это сделать, но я так и не нашел ни одного учебника, образца, документации и даже приложения, которое бы это делало ... до недавнего времени:

https://play.google.com/store/apps/details?id=com.github.ericytsang.screenfilter.app.android.

Фактически, это приложение, кажется, может рисовать везде, в отличие от разрешения SAW. Он отображается даже поверх приложения настроек и системных диалогов, в то время как разрешение SAW не разрешено как таковое.

Эта проблема

К сожалению, поскольку доступность довольно уникальна и редко используется, как я уже писал, я не мог найти, как это работает с рисованием поверх других приложений.

Что я нашел

Единственное, что я знаю, это то, что это приложение каким-то образом это делает, и вот что оно показывает, когда просит предоставить его:

введите описание изображения здесь

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

Вопросы

  1. Как AccessibilityService работает поверх других приложений?

  2. Работает ли это так же, как разрешение SAW? Можете ли вы, например, обрабатывать события касания к тому, что он рисует?

  3. Какие есть ограничения на его использование, если они есть?


person android developer    schedule 12.04.2021    source источник
comment
При чем здесь зависимости от maven?   -  person tyczj    schedule 12.04.2021
comment
@tyczj Как вы думаете, почему это как-то связано с зависимостями maven? Почему голос против? Я нигде не упоминал maven.   -  person android developer    schedule 12.04.2021
comment
Ваш титул How come maven dependencies can't be used? Также я не голосовал против   -  person tyczj    schedule 12.04.2021
comment
@tyczj Ой, извините за это. Исправлено сейчас. Заголовок предыдущего сообщения, который я сделал (здесь: stackoverflow.com/questions/66983761/) каким-то образом попали сюда, и я не заметил. Пожалуйста, больше не голосуйте против :(   -  person android developer    schedule 12.04.2021
comment
Итак, codelab для службы доступности: codelabs.developers.google.com / codelabs /, а где текст, вызывающий WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY, не был найден при поиске?   -  person Morrison Chang    schedule 20.04.2021
comment
@MorrisonChang Спасибо. Обновлен ответ, в котором упоминалось об этом. В следующий раз, пожалуйста, создайте новый ответ, чтобы я мог назначить награду.   -  person android developer    schedule 22.04.2021
comment
Я чувствовал, что вопрос был немного расфокусированным, но все же ценным. См. Также: Сколько исследовательских усилий ожидается от пользователей Stack Overflow? На кодовую таблицу имеется ссылка в нижней части Android Developer - Создайте свою собственную страницу службы специальных возможностей   -  person Morrison Chang    schedule 22.04.2021
comment
@MorrisonChang Извини. Иногда мне не удается найти информацию. :(   -  person android developer    schedule 22.04.2021


Ответы (2)


Используя TYPE_ACCESSIBILITY_OVERLAY как type в представлении из WindowManager.LayoutParams при добавлении внутри службы доступности, похоже, добивается цели. Я сделал быстрый тест, и окно наложения было показано даже в меню настроек. Окно наложения также получило события касания. Это работало также без разрешения SYSTEM_ALERT_WINDOW в манифесте, а также без интерактивной настройки пользователем разрешения Отображать поверх других приложений. Я проводил тестирование с использованием целевого SDK 29.

Извините, я не могу ответить на ваш третий вопрос о том, какие конкретно ограничения применяются.


РЕДАКТИРОВАТЬ: просмотрев старый учебник Google здесь, вот небольшой пример:

GlobalActionBarService.java

public class GlobalActionBarService extends AccessibilityService {
    FrameLayout mLayout;

    @Override
    protected void onServiceConnected() {
        // Create an overlay and display the action bar
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        mLayout = new FrameLayout(this);
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
        lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
        lp.format = PixelFormat.TRANSLUCENT;
        lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
        lp.gravity = Gravity.TOP;
        LayoutInflater inflater = LayoutInflater.from(this);
        inflater.inflate(R.layout.action_bar, mLayout);
        wm.addView(mLayout, lp);
    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
    }

    @Override
    public void onInterrupt() {
    }
}

манифест

<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
    package="com.lb.myapplication">

    <application
        android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication" tools:ignore="AllowBackup">
        <activity
            android:name=".MainActivity" android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".GlobalActionBarService" android:exported="false"
            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/global_action_bar_service" />
        </service>
    </application>

</manifest>

global_action_bar_service.xml

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault"
    android:canPerformGestures="true" android:canRetrieveWindowContent="true" />

action_bar.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="wrap_content" android:orientation="horizontal">

    <Button
        android:id="@+id/power" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="@string/power" />

    <Button
        android:id="@+id/volume_up" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="@string/volume" />

    <Button
        android:id="@+id/scroll" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="@string/scroll" />

    <Button
        android:id="@+id/swipe" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="@string/swipe" />
</LinearLayout>
person Thomas    schedule 18.04.2021
comment
Как Вы этим пользуетесь? Не могли бы вы поделиться с ним минимальным кодом? Может даже образец на Github? Или это точно так же, как использовать SAW? - person android developer; 19.04.2021
comment
Хорошо, я нашел его и отредактировал ваш ответ, включив в него образец. - person android developer; 22.04.2021
comment
Если можете, объясните, пожалуйста, даже то, что я редактировал, ответы на вопросы и что там важного. - person android developer; 22.04.2021
comment
@androiddeveloper Хорошая находка! Тем временем я загрузил небольшой пример на github. На самом деле это не сильно отличается от найденного вами примера. Важнейшая часть - добавить представление с типом TYPE_ACCESSIBILITY_OVERLAY. Если ваши вопросы действительно касаются того, как все это работает внутри, я не могу на них ответить. - person Thomas; 22.04.2021
comment
Мне интересно, какой части тега службы доступности достаточно для способности, подобной SAW. Кстати, ваша ссылка не работает. - person android developer; 23.04.2021
comment
@androiddeveloper Извините, я не понял, что репозиторий github все еще является частным, теперь он должен работать. Я сбит с толку целью ваших вопросов. Я думал, вы ищете способ отображать контент выше всех других приложений, включая пользовательский интерфейс системных настроек. Я знаю, что единственный способ добиться этого - в контексте службы доступности, как описано выше. Что касается минимального набора кода, который вам понадобится для вашего конкретного сценария, я предлагаю поэкспериментировать с примерами. Например. вы можете удалить метаданные main activity и accessibilityservice и при этом заставить наложение работать. - person Thomas; 24.04.2021
comment
Я не могу импортировать это сейчас. Похоже, что для открытия Android Studio не хватает многих важных файлов. - person android developer; 01.05.2021
comment
@androiddeveloper. Действительно, код на github не включает файлы конфигурации проекта и т. д. Однако он включает полное дерево src / main. Вы можете взять код в качестве примера и при необходимости перенести его в свой проект. Если вы обнаружите проблемы с кодом, я предлагаю обсудить их на github. - person Thomas; 02.05.2021
comment
@androiddeveloper Привет, я скопировал ваш код, он работает нормально, но я не могу удалить WindowManager представление, я пытаюсь wm.removeView(mLayout); он не работает, на экране все еще есть кнопки. Вы можете мне помочь? Большое спасибо. - person hungcuiga1; 13.06.2021

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

    val typeApplication =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
        else
            WindowManager.LayoutParams.TYPE_PHONE

    val layoutParams = WindowManager.LayoutParams(
        windowWidth,
        ViewGroup.LayoutParams.WRAP_CONTENT,
        typeApplication,
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT
    )
    // inflater view with above layoutParams variable

Приложение предоставило разрешение наложения и убедитесь, что специальные возможности включены в настройках устройства (Настройка- ›Специальные возможности -› Включить приложение). Или используйте это намерение, чтобы перейти к нему.

Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)

. Вы можете проверить разрешение наложения с помощью следующего кода

  // check
  Settings.canDrawOverlays(applicationContext)
  // Use this intent to enable permision
  Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
         Uri.parse("package:$packageName"))

Работает ли это так же, как разрешение SAW? Можете ли вы, например, обрабатывать события касания на том, что он рисует? Я никогда раньше не использовал SAW, поэтому я не уверен в этом вопросе.

Надеюсь помочь вам!

person Duc Thang    schedule 21.04.2021
comment
Другие люди здесь написали, что я должен использовать вместо этого TYPE_ACCESSIBILITY_OVERLAY. Я не вижу, чтобы это упоминалось в вашем коде. Вы проверили то, что написали? - person android developer; 21.04.2021
comment
Конечно, код используется в моем проекте. Вы можете увидеть это здесь, play.google.com/store/apps /details?id=com.tailt.new_base - person Duc Thang; 21.04.2021
comment
Похоже на классное приложение, но у него есть 3 проблемы: 1. У него есть разрешение SAW, по крайней мере, заявленное как таковое. 2. Я не могу пройти через предоставление разрешения доступности. Он зацикливается на нем, всегда просит об этом. Я считаю это серьезной ошибкой. 3. По-прежнему предпочитаю исходный код. - person android developer; 21.04.2021