You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止无障碍服务点击悬浮气泡内的控件?

问题描述

我正在为项目实现自动点击功能,希望无障碍服务启动运行时无法与悬浮气泡交互,但目前仍能点击气泡内的按钮。以下是相关代码:

onCreate Bubble Service

override fun onCreate() {
        super.onCreate()

        val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "layout_bubble:service")

        mBubbleView = LayoutInflater.from(this).inflate(R.layout.layout_bubble, null)

        mBubbleParams = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                        WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or
                        WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
                        WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
                PixelFormat.TRANSLUCENT
            )
        } else {
            WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT
            )
        }

        mBubbleParams?.gravity = Gravity.CENTER_VERTICAL or Gravity.START

        mWindowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
        mWindowManager?.addView(mBubbleView, mBubbleParams)

    }

AutoClick Service

override fun onServiceConnected() {
        super.onServiceConnected()
        autoClickService = this
        startService(Intent(this, AutoClickService::class.java)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
    }

    fun click(x: Float, y: Float) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return
        val path = Path()
        path.moveTo(x, y)
        val builder = GestureDescription.Builder()
        val gestureDescription = builder
            .addStroke(GestureDescription.StrokeDescription(path, 0L, 10L))
            .build()
        this.dispatchGesture(gestureDescription, null, null)
    }

start Auto Click

if (autoClickService != null) {
       autoClickService?.click(x,y)
       Thread.sleep(40L)
   }
解决方案

核心思路是根据无障碍服务的运行状态,拦截悬浮气泡的触摸事件,阻止内部按钮响应点击。推荐两种实现方式:

方法一:视图层级拦截触摸事件(最简实现)

直接在悬浮气泡的根视图上添加触摸拦截逻辑,当无障碍服务处于运行状态时,消费所有触摸事件,不让事件传递到内部按钮。

修改BubbleService的onCreate方法,添加触摸监听:

override fun onCreate() {
    super.onCreate()

    val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
    mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "layout_bubble:service")

    mBubbleView = LayoutInflater.from(this).inflate(R.layout.layout_bubble, null)

    // 新增:触摸拦截逻辑
    mBubbleView.setOnTouchListener { _, _ ->
        // 当无障碍服务已启动(autoClickService不为null),拦截所有触摸事件
        autoClickService != null
    }

    // ... 原有LayoutParams代码 ...

    mWindowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
    mWindowManager?.addView(mBubbleView, mBubbleParams)
}

方法二:动态修改WindowManager参数

通过修改悬浮窗口的布局参数,在无障碍服务运行时添加FLAG_NOT_TOUCHABLE标记,让整个窗口无法接收触摸事件。

1. 在无障碍服务中通知状态变化

修改AutoClickService的生命周期方法,通知气泡服务当前状态:

override fun onServiceConnected() {
    super.onServiceConnected()
    autoClickService = this
    startService(Intent(this, AutoClickService::class.java).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
    // 通知气泡服务:无障碍已启动
    updateBubbleTouchState(false)
}

override fun onDestroy() {
    super.onDestroy()
    autoClickService = null
    // 通知气泡服务:无障碍已停止
    updateBubbleTouchState(true)
}

// 用广播或全局接口传递状态,这里示例用广播
private fun updateBubbleTouchState(isTouchable: Boolean) {
    val intent = Intent("com.your.package.ACCESSIBILITY_STATE_CHANGE")
    intent.putExtra("is_touchable", isTouchable)
    sendBroadcast(intent)
}

2. 气泡服务接收状态并更新参数

在BubbleService中注册广播接收器,动态修改窗口参数:

private val accessibilityStateReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        intent?.getBooleanExtra("is_touchable", true)?.let {
            updateBubbleTouchable(it)
        }
    }
}

override fun onCreate() {
    // ... 原有代码 ...
    // 注册广播接收器
    registerReceiver(accessibilityStateReceiver, IntentFilter("com.your.package.ACCESSIBILITY_STATE_CHANGE"))
}

private fun updateBubbleTouchable(isTouchable: Boolean) {
    mBubbleParams?.let { params ->
        if (isTouchable) {
            // 恢复可触摸:移除NOT_TOUCHABLE标记
            params.flags = params.flags and WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE.inv()
            // 恢复原有外部触摸监听标记
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                params.flags = params.flags or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
            }
        } else {
            // 设置不可触摸:添加NOT_TOUCHABLE标记
            params.flags = params.flags or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
            // 移除外部触摸监听标记
            params.flags = params.flags and WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH.inv()
        }
        // 更新窗口参数
        mWindowManager?.updateViewLayout(mBubbleView, params)
    }
}

override fun onDestroy() {
    super.onDestroy()
    unregisterReceiver(accessibilityStateReceiver)
}
推荐方案

优先选择方法一,实现简单且无需跨服务通信,直接通过autoClickService的非空判断就能精准控制触摸拦截逻辑,避免额外的广播或接口依赖。

内容的提问来源于stack exchange,提问作者dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 07:57:06