Search code examples
androidbluetoothandroid-sourceandroid-bluetoothhfp

How to use bluetooth HFP profile in android programmatically?


Here I am trying to connect two android devices using Bluetooth classic and transfer calls through HFP profile.

If Device A has an incoming call, I need to notify Device B and accept/decline from the device B side and even need to talk from device B side.

I have made changes from source side in Bluetooth configs to enable A2DP sink and HF role (disabled AG role) for HFP profile in Device B.

I am confused about How AT commands works. I have to pass AT commands through output stream (Bluetooth classic connection).

Is it enough just pass AT commands(as per HFP document) to accept the call or Do I have to handle calls in the Device B side based on received AT command? I am creating an app for this work.

And also calls automatically will stream through the connection if the call accepted through AT command or Do i have to manually do something for this from the app level?


Solution

  • Android framework provide good support for HFP.

    1. AG role: BluetoothHeadset. Most phone act as AG role, and the phone app will call BluetoothHeadset API to act as AG role. This profile is enabled by default.
    2. HF role: BluetoothHeadsetClient. This API is hided, cannot be used by third apps. For most phone, no app will handle as HF role. So you need to develep an APP to do this. And android cars, it can act as HF role to connect with an phone. There is an example from AOSP CarSystemUI. This profile is disabled by default. You should enable this profile by overlay profile_supported_hfpclient to ture.

    As how to act as an HF role:

    • Connect to the HFP profile, get an BluetoothHeadsetClient:
    
        private BluetoothHeadsetClient mBluetoothHeadsetClient;
        private final ServiceListener mHfpServiceListener = new ServiceListener() {
            @Override
            public void onServiceConnected(int profile, BluetoothProfile proxy) {
                if (profile == BluetoothProfile.HEADSET_CLIENT) {
                    mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
                }
            }
    
            @Override
            public void onServiceDisconnected(int profile) {
                if (profile == BluetoothProfile.HEADSET_CLIENT) {
                    mBluetoothHeadsetClient = null;
                }
            }
        };
    
       mAdapter.getProfileProxy(context.getApplicationContext(), mHfpServiceListener,
         BluetoothProfile.HEADSET_CLIENT);
    
    
    • Connect to the remote device:
       mBluetoothHeadsetClient.connect(remoteDevice)
    
    • Monitor the connection status, call changes, ag events:
       IntentFilter filter = new IntentFilter();
       filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
       filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT);
            mContext.registerReceiver(this, filter);
       filter.addAction(BluetoothHeadsetClient.ACTION_CALL_CHANGED);
            mContext.registerReceiver(this, filter);
    
    • Trigger an call, accept an call or send vendor AT command:
       mBluetoothHeadsetClient.dail
       mBluetoothHeadsetClient.acceptCall
       mBluetoothHeadsetClient.sendVendorAtCommand
    

    Android provide high level APIs, and you don't need to send a AT comand to accept the call.