Прием звонка через Bluetooth-гарнитуру
Я работаю над VoIP-Android-приложением. Я хотел бы принимать и отклонять вызовы через подключенную Bluetooth-гарнитуру в Activity.
Что я уже пробовал:
Использование мультимедийного сеанса для получения нажатий мультимедийных кнопок.
Проблема: если мы запускаем BluetoothSCO, мы не получаем никаких нажатий кнопок мультимедиа. Если мы не запускаем BluetoothSCO, мы получаем нажатия кнопок мультимедиа, но мы не можем различить длинные и короткие нажатия кнопок, потому что время простоя всегда равно 0, код ключа всегда KEYCODE_MEDIA_PLAY, а за ACTION_DOWN сразу следует ACTION_UP. Эти проблемы возникают, только если мы подключены через Bluetooth. Если мы подключены к кабельной гарнитуре, мы получаем соответствующие коды клавиш (KEYCODE_HEADSETHOOK), и время простоя не равно 0.
Использование BroadcastReceiver для прослушивания изменений соединения Bluetooth SCO.
private val scoReceiver = object : BroadcastReceiver() { fun onReceive(context: Context, intent: Intent) { val state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1) val previousState = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE, -1) if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED && previousState == AudioManager.SCO_AUDIO_STATE_CONNECTED) { Log.e(TAG, "SCO Disconnected") hangupCall() } } } protected fun onStart() { super.onStart() val intentFilter = IntentFilter() intentFilter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED) registerReceiver(scoReceiver, intentFilter) }
При таком подходе я могу определить, когда пользователь хочет положить трубку, например, долгое нажатие на гарнитуру Bluetooth, потому что это вызывает отключение SCO.
Проблема: мы не можем определить, хочет ли пользователь принять входящий звонок.
Использование dispatchKeyEvent, onKeyDown и onKeyUp.
Проблема: им никогда не звонят вообще.
У кого-нибудь есть совет или лучшая практика, как правильно обращаться с Bluetooth-гарнитурами? Любая помощь очень ценится. Заранее спасибо!
3 ответа
Эти события обрабатываются внутри HeadsetStateMachine (в пакетах / приложениях /Bluetooth).
Эти события перенаправляются в интерфейс IBluetoothHeadsetPhone. Одно приложение, в которое пересылаются все события, определяется во время выполнения с помощью следующего кода привязки в HeadsetStateMachine.java. Это позволяет производителям телефонов пересылать их в пользовательское приложение телефона вместо приложения по умолчанию в тех случаях, когда приложение по умолчанию не используется.
Intent intent = new Intent(IBluetoothHeadsetPhone.class.getName());
intent.setComponent(intent.resolveSystemService(context.getPackageManager(), 0));
if (intent.getComponent() == null || !context.bindService(intent, mConnection, 0)) {
Log.e(TAG, "Could not bind to Bluetooth Headset Phone Service");
}
Чтобы события перенаправлялись в ваше приложение, а не в телефонное приложение по умолчанию, вам нужно изменить код aosp. Вам нужно будет перехватить события на одном из HeadsetStateMachine, прокси BluetoothHeadsetPhone или в приложении телефона.
К сожалению, то, что вы ищете, в настоящее время невозможно без изменения кода aosp. Некоторые гарнитуры, такие как Plantronics, имеют пользовательские события BT, которые перенаправляются во все приложения - некоторые из существующих приложений VoIP поддерживают эти настраиваемые намерения для поддержки по крайней мере ответа на вызовы для некоторых гарнитур.
Во время обычного и виртуального голосового вызова (включая звонок) все события кнопок блока гарнитуры Bluetooth обрабатываются службой Bluetooth-гарнитуры внутренне и не транслируются как события кнопок. Bluetooth Headset Service перенаправляет эти события в инфраструктуру Telecom (answer/hangupCall).
Вы должны использовать Android Telecom API и реализоватьandroid.telecom.ConnectionService
иandroid.telecom.Connection
где вы должны переопределить обратный вызов onAnswer(), который будет вызываться при попытке ответить на вызов через Bluetooth-гарнитуру.
Подробнее читайте в документах — https://developer.android.com/guide/topics/connectivity/telecom/selfManaged.