Прием вызова через Bluetooth-гарнитуру

Я работаю над VoIP-Android-приложением. Я хотел бы принять и отклонить вызовы через подключенную Bluetooth-гарнитуру в Activity.

То, что я пробовал до сих пор:

  • Использование мультимедийного сеанса для получения щелчков кнопки Media Button.

    Проблема. Если мы запустим BluetoothSCO, мы не получим никаких кликов на Media Button. Если мы не запускаем BluetoothSCO, мы получаем клики Media Button, но мы не можем отличать длинные и короткие нажатия кнопок, потому что время простоя всегда равно 0, код ключа всегда KEYCODE_MEDIA_PLAY, а ACTION_DOWN немедленно следует ACTION_UP. Эти проблемы возникают только при подключении через Bluetooth. Если мы подключены к кабельной гарнитуре, мы получаем соответствующие коды клавиш (KEYCODE_HEADSETHOOK), а время простоя не равно 0.

  • Использование BroadcastReceiver для прослушивания изменений соединения SCO Bluetooth.

    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? Любая помощь очень ценится. Заранее спасибо!

Ответ 1

Во время обычного и виртуального голосового вызова (включая звонок) все события кнопок Bluetooth гарнитуры обрабатываются службой Bluetooth Headset Service внутри и не транслируются как события кнопок. Служба Bluetooth-гарнитуры перенаправляет эти события в инфраструктуру Telecom (ответ/hangupCall).

Ответ 2

Эти события обрабатываются внутри устройства 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");
    }

Чтобы события пересылались в ваше приложение вместо стандартного телефонного приложения, вам придется изменить код ASP. Вам нужно будет перехватить события в одном из профайлов HeadsetStateMachine, BluetoothHeadsetPhone или в приложении телефона.

К сожалению, то, что вы ищете, в настоящее время невозможно без изменения кода ASP. Некоторые гарнитуры, такие как Plantronics, имеют пользовательские события BT, которые перенаправляются во все приложения - некоторые из существующих VoIP-приложений поддерживают эти пользовательские намерения для поддержки, как минимум, для вызовов некоторых гарнитур.