Android 蓝牙 hfp连接


该文章基于Android Q

1 hfp简单介绍

HFP (Hands-free Profile),让蓝牙设备(如蓝牙耳机)可以控制电话,如接听、挂断、拒接、语音拨号等,拒接、语音拨号要看蓝牙耳机及电话是否支持。

HFP定义了音频网关(AG)和免提组件(HF)两个角色:
音频网关(AG) – 该设备为音频(特别是手机)的输入/输出网关。
免提组件(HF) – 该设备作为音频网关的远程音频输入/输出机制,并可提供若干遥控功能。

2 手机音频连接

点击手机音频进行连接时,调用onPreferenceClick。

    @Override
    public boolean onPreferenceClick(Preference preference) {
    
    
        ......
        SwitchPreference profilePref = (SwitchPreference) preference;
        if (profilePref.isChecked()) {
    
    
            enableProfile(profile);
        } else {
    
    
            disableProfile(profile);
        }
        refreshProfilePreference(profilePref, profile);
        return true;
    }
    private void enableProfile(LocalBluetoothProfile profile) {
    
    
        final BluetoothDevice bluetoothDevice = mCachedDevice.getDevice();
        if (profile instanceof PbapServerProfile) {
    
    
            bluetoothDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
            // We don't need to do the additional steps below for this profile.
            return;
        }
        if (profile instanceof MapProfile) {
    
    
            bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
        }
        profile.setPreferred(bluetoothDevice, true);
        mCachedDevice.connectProfile(profile);
    }

frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java

    public void connectProfile(LocalBluetoothProfile profile) {
    
    
        mConnectAttempted = SystemClock.elapsedRealtime();
        connectInt(profile);
        // Refresh the UI based on profile.connect() call
        refresh();
    }

    synchronized void connectInt(LocalBluetoothProfile profile) {
    
    
        if (!ensurePaired()) {
    
    
            return;
        }
        if (profile.connect(mDevice)) {
    
    
            if (BluetoothUtils.D) {
    
    
                Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
            }
            return;
        }
        Log.i(TAG, "Failed to connect " + profile.toString() + " to " + getName());
    }

frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java

    public boolean connect(BluetoothDevice device) {
    
    
        if (mService == null) {
    
    
            return false;
        }
        return mService.connect(device);
    }

frameworks/base/core/java/android/bluetooth/BluetoothHeadset.java

    public boolean connect(BluetoothDevice device) {
    
    
        if (DBG) log("connect(" + device + ")");
        final IBluetoothHeadset service = mService;
        if (service != null && isEnabled() && isValidDevice(device)) {
    
    
            try {
    
    
                return service.connect(device);
            } catch (RemoteException e) {
    
    
                Log.e(TAG, Log.getStackTraceString(new Throwable()));
                return false;
            }
        }
        if (service == null) Log.w(TAG, "Proxy not attached to service");
        return false;
    }

packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java

private static class BluetoothHeadsetBinder extends IBluetoothHeadset.Stub{
    
    
		......
        public boolean connect(BluetoothDevice device) {
    
    
            HeadsetService service = getService();
            if (service == null) {
    
    
                return false;
            }
            return service.connect(device);
        }
}

public boolean connect(BluetoothDevice device) {
    
    
	......
	stateMachine.sendMessage(HeadsetStateMachine.CONNECT, device);
}

packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java

class Disconnected extends HeadsetStateBase {
    
    
	public boolean processMessage(Message message) {
    
    
        switch (message.what) {
    
    
            case CONNECT:
                BluetoothDevice device = (BluetoothDevice) message.obj;
                stateLogD("Connecting to " + device);
                ......
                if (!mNativeInterface.connectHfp(device)) {
    
    
                    stateLogE("CONNECT failed for connectHfp(" + device + ")");
                    // No state transition is involved, fire broadcast immediately
                    broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
                            BluetoothProfile.STATE_DISCONNECTED);
                    break;
                }
                retryConnectCount++;
                transitionTo(mConnecting);
                break;
}

最后状态机Disconnected->Connecting

packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetNativeInterface.java

    public boolean connectHfp(BluetoothDevice device) {
    
    
        return connectHfpNative(Utils.getByteAddress(device));
    }

packages/apps/Bluetooth/jni/com_android_bluetooth_hfp.cpp

static jboolean connectHfpNative(JNIEnv* env, jobject object,
                                 jbyteArray address) {
    
    
  ......
  ALOGI("%s: device %s", __func__, ((RawAddress*)addr)->ToString().c_str());
  bt_status_t status = sBluetoothHfpInterface->Connect((RawAddress*)addr);
  if (status != BT_STATUS_SUCCESS) {
    
    
    ALOGE("Failed HF connection, status: %d", status);
  }
  env->ReleaseByteArrayElements(address, addr, 0);
  return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

vendor/qcom/opensource/commonsys/system/bt/btif/src/btif_hf.cc

bt_status_t HeadsetInterface::Connect(RawAddress* bd_addr) {
    
    
  CHECK_BTHF_INIT();
  return btif_queue_connect(UUID_SERVCLASS_AG_HANDSFREE, *bd_addr, connect_int,
                                  btif_max_hf_clients);
}

3 连接状态

当协议栈连接状态改变会回调com_android_bluetooth_hfp.cpp中的方法ConnectionStateCallback()。
packages/apps/Bluetooth/jni/com_android_bluetooth_hfp.cpp

  void ConnectionStateCallback(
      bluetooth::headset::bthf_connection_state_t state,
      RawAddress* bd_addr) override {
    
    
    ALOGI("%s %d for %s", __func__, state, bd_addr->ToString().c_str());
	......
    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
                                 (jint)state, addr.get());
  }

packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetNativeInterface.java

    void onConnectionStateChanged(int state, byte[] address) {
    
    
        HeadsetStackEvent event =
                new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED, state,
                        getDevice(address));
        sendMessageToService(event);
    }

    private void sendMessageToService(HeadsetStackEvent event) {
    
    
        HeadsetService service = HeadsetService.getHeadsetService();
        if (service != null) {
    
    
            service.messageFromNative(event);
        } else {
    
    
            // Service must call cleanup() when quiting and native stack shouldn't send any event
            // after cleanup() -> cleanupNative() is called.
            Log.wtfStack(TAG, "FATAL: Stack sent event while service is not available: " + event);
        }
    }

packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java

    void messageFromNative(HeadsetStackEvent stackEvent) {
    
    
        Objects.requireNonNull(stackEvent.device,
                "Device should never be null, event: " + stackEvent);
        synchronized (mStateMachines) {
    
    
            HeadsetStateMachine stateMachine = mStateMachines.get(stackEvent.device);
            ......
            stateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT, stackEvent);
        }
    }

packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java

    class Connecting extends HeadsetStateBase {
    
    
        public boolean processMessage(Message message) {
    
    
            switch (message.what) {
    
    
            	......
            	case STACK_EVENT:
            		switch (event.type) {
    
    
                        case HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED:
                        	processConnectionEvent(message, event.valueInt);
                            break;
                ......
            }
        }

        public void processConnectionEvent(Message message, int state) {
    
    
            stateLogD("processConnectionEvent, state=" + state);
            switch (state) {
    
    
                ......
                case HeadsetHalConstants.CONNECTION_STATE_SLC_CONNECTED:
                    stateLogD("SLC connected");
                    retryConnectCount = 0;
                    transitionTo(mConnected);
                    break;
                ......
            }
        }

状态机Connecting->Connected,执行enter

    class Connected extends ConnectedBase {
    
    
		......
        public void enter() {
    
    
            ......
            broadcastStateTransitions();
        }

发送broadcast BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED

        void broadcastConnectionState(BluetoothDevice device, int fromState, int toState) {
    
    
            stateLogD("broadcastConnectionState " + device + ": " + fromState + "->" + toState);
            mHeadsetService.onConnectionStateChangedFromStateMachine(device, fromState, toState);
            Intent intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
            intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, fromState);
            intent.putExtra(BluetoothProfile.EXTRA_STATE, toState);
            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
            mHeadsetService.sendBroadcastAsUser(intent, UserHandle.ALL,
                    HeadsetService.BLUETOOTH_PERM);
        }

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/a13821684483/article/details/100929838