Android - Можно ли рисовать на поверхности, которая будет игнорироваться (не блокироваться) устройством записи экрана? - PullRequest
0 голосов
/ 10 апреля 2020

Фон

Я создаю приложение Android, которое обеспечивает обратную связь в реальном времени по вопросам доступности, выделяя и маркируя их с помощью Canvas, прикрепленного к окну, с помощью TYPE_APPLICATION_OVERLAY или TYPE_SYSTEM_ERROR в зависимости от версия ОС. Это работало нормально, когда я просто использовал AccessibilityService для получения событий специальных возможностей, поскольку я мог предотвратить обнаружение моих представлений во время анализа.

Проблема

Я недавно пытался добавить поддержку для обнаружения новых типов проблем. например, контраст текста или фона или размер текста путем записи экрана и использования оптического распознавания текста для определения текста и его свойств. Оптическое распознавание текста работает хорошо, и я могу обнаружить любой текст на экране (включая текст, вставленный в изображение), но теперь моя система выделения и маркировки воспринимается записью экрана в обратной связи l oop, вызывая чтобы выделить метки над текстовым блоком как проблемы, что приводит к пузырьковому эффекту, который оживляет что-то вроде

                                                                                +-----+
                                                                                |Issue|
                                                              +-----+           +-----+
                                                              |Issue|           |     |
                                            +-----+           +-----+           +-----+
                                            |Issue|           |     |                
                =>        +-----+ =>        +-----+ =>        +-----+ =>        +-----+
                          |Issue|           |Issue|           |Issue|           |Issue|
                  +-------------+   +-------------+   +-------------+   +-------------+
  Some text       | Some text   |   | Some text   |   | Some text   |   | Some text   |
                  +-------------+   +-------------+   +-------------+   +-------------+

Вопрос

Есть ли способ скрыть свое наложение от записи ?

Что я пробовал

Я добавил WindowManager.LayoutParams.FLAG_SECURE в список флагов и, несмотря на то, что ничего не записывалось, он все равно записывал как исходный текст, так и оверлейный текст

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

Код экрана записи

В активности

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val mediaProjectionManager =
            ContextCompat.getSystemService(this, MediaProjectionManager::class.java)
    val intent = mediaProjectionManager?.createScreenCaptureIntent()
    startActivityForResult(intent, REQUEST_CODE)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    // Skip error handling for brevity

    notifyServiceOfScreenRecording(resultCode, data)

    finish()
}

Расход записи

// Again, safety checks removed for brevity
val mediaProjectionManager = ContextCompat.getSystemService(mContext, MediaProjectionManager::class.java)

val projection: MediaProjection =
        mediaProjectionManager.getMediaProjection(screenRecordingCode, screenRecordingIntent)

val imageReader = ImageReader.newInstance(mScreenWidth, mScreenHeight, PixelFormat.RGBA_8888, 1)
imageReader.setOnImageAvailableListener({ reader ->
    if (mIsProcessing) {
        reader.acquireLatestImage().close()
    } else {
        mIsProcessing = true
        reader.acquireLatestImage()?.use(this::processImage)
    }
}, null)

projection.createVirtualDisplay(
        "Virtual Display",
        // These are computed with Context.getDisplayMetrics()
        mScreenWidth, mScreenHeight,
        mScreenDensity,
        DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
        imageReader.surface,
        null /*Callbacks*/,
        null /*Handler*/)

projection.registerCallback(object: MediaProjection.Callback() {
    override fun onStop() {
        super.onStop()
        pauseProcessing();
    }
}, null)

Наложение кода

val overlayType: Int =
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            WindowManager.LayoutParams.TYPE_SYSTEM_ERROR
        } else {
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
        }
val overlayFlags =
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
        WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE

windowLayoutParams = WindowManager.LayoutParams(
        WindowManager.LayoutParams.MATCH_PARENT,
        WindowManager.LayoutParams.MATCH_PARENT,
        overlayType,
        overlayFlags,
        PixelFormat.TRANSLUCENT) }
mWindowLayoutParams.verticalMargin = 0f

val windowManager = context.getSystemService(AccessibilityService.WINDOW_SERVICE) as WindowManager
windowManager.addView(buildCustomRootView(), windowLayoutParams)
...