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

Android中如何检测蓝牙耳机通话按键的按压操作?

检测蓝牙耳机通话按键按压的解决方案

你遇到的核心问题是:Android 6.0+ 版本中,蓝牙通话按键的事件不再通过ACTION_CALL_BUTTON广播或onKeyDown分发,而是优先路由到活跃的MediaSession。你的代码激活了MediaSession但未设置回调处理事件,导致按键被拦截却无法收到通知。

修复步骤

  1. 为MediaSession设置Callback,重写onMediaButtonEvent方法捕获按键事件
  2. 确保MediaSession正确获取媒体按钮事件的控制权
  3. 移除无效的ACTION_CALL_BUTTON广播接收器(高版本已不再生效)

修改后的完整代码

class MainActivity : AppCompatActivity() {

    private lateinit var audioManager: AudioManager
    private var headsetDevice: AudioDeviceInfo? = null
    private lateinit var mediaSession: MediaSession

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)

        audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
        
        // 初始化MediaSession并设置事件回调
        mediaSession = MediaSession(this, packageName).apply {
            setCallback(object : MediaSession.Callback() {
                override fun onMediaButtonEvent(mediaButtonIntent: Intent): Boolean {
                    val keyEvent = mediaButtonIntent.getParcelableExtra<KeyEvent>(Intent.EXTRA_KEY_EVENT)
                    keyEvent?.let {
                        when (it.keyCode) {
                            KeyEvent.KEYCODE_CALL -> {
                                // 区分按键的按下/抬起动作
                                when (it.action) {
                                    KeyEvent.ACTION_DOWN -> Log.d(TAG, "通话按键按下")
                                    KeyEvent.ACTION_UP -> Log.d(TAG, "通话按键抬起")
                                }
                                // 返回true表示已消费事件,阻止系统默认拨号行为
                                return true
                            }
                            // 可扩展处理其他蓝牙按键,比如KEYCODE_MEDIA_PLAY_PAUSE
                        }
                    }
                    return super.onMediaButtonEvent(mediaButtonIntent)
                }
            })
            // 设置标志确保能处理媒体按键事件
            setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS or MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS)
        }
    }

    override fun onResume() {
        super.onResume()
        val devices = audioManager.availableCommunicationDevices
        Log.d(TAG, "找到 ${devices.size} 个可用通讯设备")
        headsetDevice = devices.firstOrNull { it.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO }
        headsetDevice?.let {
            Log.d(TAG, "连接通讯设备: ${it.productName}")
            if (!audioManager.setCommunicationDevice(it)) {
                Log.d(TAG, "连接耳机失败")
            }
        }
        mediaSession.isActive = true
    }

    override fun onStop() {
        super.onStop()
        headsetDevice?.let { audioManager.clearCommunicationDevice() }
        mediaSession.isActive = false
        mediaSession.release()
    }

    companion object {
        const val TAG = "HeadsetButtonDemo"
    }
}

关键说明

  • 为什么之前的代码拦截了按键却没收到通知?:你激活了MediaSession后,系统会将蓝牙按键事件优先发送给活跃的MediaSession,但你未设置Callback处理事件,导致事件被消费但无日志输出,同时默认的拨号行为被阻止。
  • 放弃ACTION_CALL_BUTTON广播依赖:Android 6.0之后,系统对这类广播的分发做了限制,仅部分系统应用能收到,第三方APP必须通过MediaSession处理。
  • 扩展按键识别:通过KeyEvent的repeatCount参数,还可以实现长按、双击等复杂按键动作的识别逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 19:00:53