Android中如何检测蓝牙耳机通话按键的按压操作?
检测蓝牙耳机通话按键按压的解决方案
你遇到的核心问题是:Android 6.0+ 版本中,蓝牙通话按键的事件不再通过ACTION_CALL_BUTTON广播或onKeyDown分发,而是优先路由到活跃的MediaSession。你的代码激活了MediaSession但未设置回调处理事件,导致按键被拦截却无法收到通知。
修复步骤
- 为
MediaSession设置Callback,重写onMediaButtonEvent方法捕获按键事件 - 确保
MediaSession正确获取媒体按钮事件的控制权 - 移除无效的
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
相关产品推荐
相关产品推荐

