简体   繁体   English

应用程序如何检测当前正在使用 SAW 权限?

[英]How do apps detect that SAW permission is currently being used?

Background背景

I've noticed many times, that when I use an app that uses SAW (system-alert-window, AKA "display over other apps) permission (example here ), and I open Chrome web browser and reach some website that requires a permission (example here , taken from here ), it won't let me grant/deny the permission:我多次注意到,当我使用使用 SAW(系统警报窗口,又名“在其他应用程序上显示”)权限的应用程序( 此处示例)时,我打开 Chrome web 浏览器并访问一些需要权限的网站(这里的例子,取自这里),它不会让我授予/拒绝许可:

在此处输入图像描述

The problem问题

I can't find how they did it, and from which Android version it's possible to check it.我找不到他们是怎么做到的,也不知道从哪个 Android 版本可以查到。

What I've found我发现了什么

Sadly as much as I've searched, I actually had more questions.遗憾的是,尽管我搜索了很多,但实际上我还有更多问题。

For example, how come the web browser can't detect which app is showing on top, and tell us to disable it?例如,为什么 web 浏览器无法检测到哪个应用显示在顶部,并告诉我们禁用它?

Or, now that Android 12 might arrive, there seem to be a new permission to block SAW ( here ):或者,现在 Android 12 可能到达,似乎有一个新的权限来阻止 SAW( 此处):

HIDE_OVERLAY_WINDOWS Added in Android S HIDE_OVERLAY_WINDOWS 添加于 Android S

public static final String HIDE_OVERLAY_WINDOWS Allows an app to prevent non-system-overlay windows from being drawn on top of it public static final String HIDE_OVERLAY_WINDOWS 允许应用防止非系统覆盖 windows 在其上绘制

Constant Value: "android.permission.HIDE_OVERLAY_WINDOWS"常数值:“android.permission.HIDE_OVERLAY_WINDOWS”

Perhaps for this case there aren't many that have asked about it, or for some reason I didn't choose the correct things to write in order to search for an answer.也许对于这种情况,没有多少人问过它,或者由于某种原因我没有选择正确的东西来写以寻找答案。

The questions问题

  1. How can I detect if some app is using SAW permission while I show something?当我展示某些内容时,如何检测某些应用程序是否正在使用 SAW 权限?

  2. Is there a way to detect which app does that?有没有办法检测哪个应用程序执行此操作?

  3. What can the API offer for this, and from which version is it available? API 可以为此提供什么,它可以从哪个版本获得?

  4. I remember I was told that accessibility can be used to draw on top.我记得有人告诉我可访问性可用于在顶部绘制。 Sadly I failed to find a tutorial on how to do this, and also of an example of such apps.遗憾的是,我没有找到有关如何执行此操作的教程,也没有找到此类应用程序的示例。 Would this API be able to detect them too?这个 API 也能检测到它们吗? Or this isn't considered as SAW?或者这不被视为 SAW? Where can I find a tutorial on how to do it, so that I could check it out?我在哪里可以找到有关如何操作的教程,以便我可以查看?

  5. Bonus: how on Android S do you use the new permission to hide SAW?奖励:如何在 Android S 上使用新权限隐藏 SAW?

  1. There is a common approach to detect a window overlay using FLAG_WINDOW_IS_OBSCURED (or FLAG_WINDOW_IS_PARTIALLY_OBSCURED for API 29+):使用FLAG_WINDOW_IS_OBSCURED (或FLAG_WINDOW_IS_PARTIALLY_OBSCURED 29+ 的 FLAG_WINDOW_IS_PARTIALLY_OBSCURED)检测 window 覆盖有一种常见的方法:
    https://stackoverflow.com/search?q=FLAG_WINDOW_IS_OBSCURED \ https://stackoverflow.com/search?q=FLAG_WINDOW_IS_OBSCURED \
  2. There is no API to detect a particular app.没有 API 来检测特定应用程序。

Regarding Chrome, you can find the implementation in the source code: ModalDialogView.java#L203关于Chrome,可以在源码中找到实现: ModalDialogView.java#L203

Actually you can ask MotionEvents if the window is obscured (an alert is being shown over them) so you can tell that you're obscured, but you cannot tell which app is doing it实际上,您可以询问 MotionEvents window 是否被遮挡(在它们上方显示警报),这样您就可以知道您被遮挡了,但您无法确定哪个应用程序正在执行此操作

There are some similar questions that has required explanations How to detect when my Activity has been obscured?有一些类似的问题需要解释如何检测我的活动何时被遮挡?

Android detect or block floating/overlaying apps Android 检测或阻止浮动/覆盖应用程序

I'm not sure about item 4, but usually application who use accessibility to reas the screen and show you something magical (like that banned Voodoo app) also require SAW permission and as much as I can remember, Accessibility services are just some callbacks.我不确定第 4 项,但通常使用可访问性来查看屏幕并向您展示一些神奇的应用程序(例如被禁止的 Voodoo 应用程序)也需要 SAW 许可,据我所知,可访问性服务只是一些回调。

  1. You put the permission in manifest and when you want to hide SAWs simply call setHideOverlayWindows(true)您将权限放在清单中,当您想隐藏 SAW 时,只需调用setHideOverlayWindows(true)

https://developer.android.google.cn/about/versions/12/features#hide-application-overlay-windows https://developer.android.google.cn/about/versions/12/features#hide-application-overlay-windows

OK I've made a sample to show all ways to detect it, including what happens when you use the new API ( setHideOverlayWindows ) to hide apps that are shown on top:好的,我制作了一个示例来展示检测它的所有方法,包括当您使用新的 API ( setHideOverlayWindows ) 隐藏顶部显示的应用程序时会发生什么:

  1. https://developer.android.com/reference/android/app/Activity#dispatchTouchEvent(android.view.MotionEvent) https://developer.android.com/reference/android/app/Activity#dispatchTouchEvent(android.view.MotionEvent)
  2. https://developer.android.com/reference/android/view/View#setOnTouchListener(android.view.View.OnTouchListener) https://developer.android.com/reference/android/view/View#setOnTouchListener(android.view.View.OnTouchListener)
  3. https://developer.android.com/reference/android/view/View#onFilterTouchEventForSecurity(android.view.MotionEvent) https://developer.android.com/reference/android/view/View#onFilterTouchEventForSecurity(android.view.MotionEvent)

manifest显现

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.lb.detect_floating_app">
    <uses-permission android:name="android.permission.HIDE_OVERLAY_WINDOWS" />
    <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.DetectFloatingApp">
        <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>
    </application>
</manifest>

MainActivity.kt主活动.kt

class MainActivity : AppCompatActivity() {
    var isObscured: Boolean? = null
    var isPartiallyObscured: Boolean? = null
    var isHidingFloatingApp = false

    @SuppressLint("ClickableViewAccessibility")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<View>(R.id.textView).setOnTouchListener(object : View.OnTouchListener {
            var isObscured: Boolean? = null
            var isPartiallyObscured: Boolean? = null

            override fun onTouch(p0: View?, ev: MotionEvent): Boolean {
                val checkIsObscured = ev.flags and MotionEvent.FLAG_WINDOW_IS_OBSCURED != 0
                val checkIsPartiallyObscured = ev.flags and MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED != 0
                if (checkIsObscured != isObscured || checkIsPartiallyObscured != isPartiallyObscured) {
                    isObscured = checkIsObscured
                    isPartiallyObscured = checkIsPartiallyObscured
                    Log.d("AppLog", "${System.currentTimeMillis()} setOnTouchListener isObscured:$isObscured isPartiallyObscured:$isPartiallyObscured")
                }
                return false
            }
        })
        findViewById<View>(R.id.toggleHideFloatingAppButton).setOnClickListener {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                isHidingFloatingApp = !isHidingFloatingApp
                window.setHideOverlayWindows(isHidingFloatingApp)
            } else
                Toast.makeText(this, "need Android API 31", Toast.LENGTH_SHORT).show()
        }
    }

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        val checkIsObscured = ev.flags and MotionEvent.FLAG_WINDOW_IS_OBSCURED != 0
        val checkIsPartiallyObscured = ev.flags and MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED != 0
        if (checkIsObscured != isObscured || checkIsPartiallyObscured != isPartiallyObscured) {
            isObscured = checkIsObscured
            isPartiallyObscured = checkIsPartiallyObscured
            Log.d("AppLog", "${System.currentTimeMillis()} dispatchTouchEvent isObscured:$isObscured isPartiallyObscured:$isPartiallyObscured")
        }
        return super.dispatchTouchEvent(ev)
    }
}

FloatingDetectorFrameLayout.kt FloatingDetectorFrameLayout.kt

class FloatingDetectorFrameLayout : FrameLayout {
    var isObscured: Boolean? = null
    var isPartiallyObscured: Boolean? = null

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)

    override fun onFilterTouchEventForSecurity(ev: MotionEvent): Boolean {
        val checkIsObscured = ev.flags and MotionEvent.FLAG_WINDOW_IS_OBSCURED != 0
        val checkIsPartiallyObscured = ev.flags and MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED != 0
        if (checkIsObscured != isObscured || checkIsPartiallyObscured != isPartiallyObscured) {
            isObscured = checkIsObscured
            isPartiallyObscured = checkIsPartiallyObscured
            Log.d("AppLog", "${System.currentTimeMillis()} onFilterTouchEventForSecurity isObscured:$isObscured isPartiallyObscured:$isPartiallyObscured")
        }
        return super.onFilterTouchEventForSecurity(ev)
    }
}

activity_main.xml activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"
    android:orientation="vertical" tools:context=".MainActivity">


    <com.lb.detect_floating_app.FloatingDetectorFrameLayout
        android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#f00"
        android:padding="100dp">

        <Button
            android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </com.lb.detect_floating_app.FloatingDetectorFrameLayout>

    <Button android:id="@+id/toggleHideFloatingAppButton"
        android:text="toggle hide floating app"
        android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在最新的 Android 上检测当前正在运行的应用程序(或前台应用程序)的统计信息? - How to detect stats on currently running Apps (or foreground App) on latest Android? 如何检查是否实际使用了Android权限? - How to check if Android Permission is actually being used? Android - 如何检查麦克风当前正被某些其他应用程序使用 - Android - How to check Microphone is currently being used by some other application 如何检测正在使用的手指数量? - How to detect number of fingers being used? 对于 Android 应用程序,如何检查特定图像视图中使用的资源 ID? - For Android apps, how do I check what resource ID is being used in a specific image view? 如何以编程方式找到FragmentActivity当前正在显示的片段? - How do I programatically find the fragment currently being shown by a FragmentActivity? 如何检测韩国是否正在使用Android应用? - How can I detect if an Android app is being used in Korea? 如何检测用户正在使用的应用程序是否是 mod apk - How to detect if the application being used by a user is mod apk or not Firebase身份验证如何检测是否正在使用物理设备? - How does Firebase Authentication detect if a physical device is being used? 有没有办法检测当前是否在 Android webview 中显示弹出窗口? - Is there a way to detect if a popup is currently being displayed in an Android webview?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM