当前位置:   article > 正文

浅谈android蓝牙电话API调用及相关代码_bluetoothheadsetclient.stub

bluetoothheadsetclient.stub

    前段时间做车机蓝牙电话的项目,接触到了部分关于蓝牙电话API的调用。

首先车机与手机端配好对,其中配置项中的手机音频和共享联系人要打开,等两端连接好后,就进入正题,

通过  adapter= BluetoothAdapter.getDefaultAdapter();拿到蓝牙适配器,然后 通过

 adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.HEADSET_CLIENT); 

设置蓝牙电话客户端的监听mProfileServiceListener,

    private final BluetoothProfile.ServiceListener mProfileServiceListener = new BluetoothProfile.ServiceListener()
{
public void onServiceConnected(int paramInt, BluetoothProfile paramBluetoothProfile)
{
mHeadsetClient = ((BluetoothHeadsetClient)paramBluetoothProfile);
}


public void onServiceDisconnected(int paramInt)
{


}
};

这样当连接好了,我们就拿到了蓝牙电话客户端的代理mHeadsetClient 。关于这部分的API,文件在frameworks/base/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl,网上链接 https://source.codeaurora.org/quic/la/platform/frameworks/base/tree/core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl?h=m。

常用的接口有

  1. boolean acceptCall(in BluetoothDevice device, int flag);
  2. boolean holdCall(in BluetoothDevice device);
  3. boolean rejectCall(in BluetoothDevice device);
  4. boolean terminateCall(in BluetoothDevice device, int index);
    boolean dial(in BluetoothDevice device, String number);

比如通过调用mHeadsetClient.dial(mDevice, "110");就可以给110打电话了。
 
 
上面是关于接口的简单调用。我们再来看看这个打电话的接口是怎么实现的。
android frameworks层给我们开放了大量的接口,供开发者使用。上面提到了IBluetoothHeadsetClient.aidl,
看文件后辍,知道是通过aidl调用来实现的,实现它的文件是 BluetoothHeadsetClient.java,
    
  1. public boolean dial(BluetoothDevice device, String number) {
  2. if (DBG) log("dial()");
  3. if (mService != null && isEnabled() &&
  4. isValidDevice(device)) {
  5. try {
  6. return mService.dial(device, number);
  7. } catch (RemoteException e) {
  8. Log.e(TAG, Log.getStackTraceString(new Throwable()));
  9. }
  10. }
  11. if (mService == null) Log.w(TAG, "Proxy not attached to service");
  12. return false;
  13. }
我们发现,实现打电话功能函数是dial,而真正实现打电话的是mService.dial(device, number); 这个mService的定义
private IBluetoothHeadsetClient mService;
当我们获取得到一个BluetoothHeadsetClient时,会调用BluetoothHeadsetClient的构造函数,它会执行一个doBind(),
  1. boolean doBind() {
  2. Intent intent = new Intent(IBluetoothHeadsetClient.class.getName());
  3. ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
  4. intent.setComponent(comp);
  5. if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
  6. android.os.Process.myUserHandle())) {
  7. Log.e(TAG, "Could not bind to Bluetooth Headset Client Service with " + intent);
  8. return false;
  9. }
  10. return true;
  11. }
当绑定服务成功时,mService 被赋值
  1. private ServiceConnection mConnection = new ServiceConnection() {
  2. @Override
  3. public void onServiceConnected(ComponentName className, IBinder service) {
  4. mService = IBluetoothHeadsetClient.Stub.asInterface(service);  
        }
  1. @Override
  2. public void onServiceDisconnected(ComponentName className) { }
  3. };
原来我们获得一个IBluetoothHeadsetClient 对象时,系统会去绑定一个服务,并获取这个服务的代理,而这个服务才是真正实现打电话的地方。
这个服务实现是在packages/apps/Bluetooth/src/com/android/bluetooth/hfpclient/HeadsetClientService.java, 绑定的服务是个内部类BluetoothHeadsetClientBinder 
它调用了
  1. boolean dial(BluetoothDevice device, String number) {
  2. enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
  3. int connectionState = mStateMachine.getConnectionState(device);
  4. if (connectionState != BluetoothProfile.STATE_CONNECTED &&
  5. connectionState != BluetoothProfile.STATE_CONNECTING) {
  6. return false;
  7. }
  8. Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER);
  9. msg.obj = number;
  10. mStateMachine.sendMessage(msg);
  11. return true;
  12. }
仔细一看,怎么又冒出个mStateMachine,这是安卓中的状态机,我们跟进到HeadsetClientStateMachine.java文件中去。
mStateMachine将信息发出(mStateMachine.sendMessage(msg)),此时蓝牙电话状态机状态为Connected ,进入processMessage
流程分支
  1. case DIAL_NUMBER:
  2. if (dialNative((String) message.obj)) {
  3. addQueuedAction(DIAL_NUMBER, message.obj);
  4. } else {
  5. Log.e(TAG, "ERROR: Cannot dial with a given number:" + (String) message.obj);
  6. }
  7. break;
我们终于发现,实现打电话的方法是dialNative, 一个本地方法。
  1. static jboolean dialNative(JNIEnv *env, jobject object, jstring number_str) {
  2. bt_status_t status;
  3. const char *number = NULL;
  4. if (!sBluetoothHfpClientInterface) return JNI_FALSE;
  5. if (number_str != NULL) {
  6. number = env->GetStringUTFChars(number_str, NULL);
  7. }
  8. if (number != NULL) {
  9. if ( (status = sBluetoothHfpClientInterface->dial(number)) != BT_STATUS_SUCCESS) {
  10. ALOGE("Failed to dial, status: %d", status);
  11. }
  12. } else {
  13. if ( (status = sBluetoothHfpClientInterface->dial("")) != BT_STATUS_SUCCESS) {
  14. ALOGE("Failed to dial, status: %d", status);
  15. }
  16. }
  17. if (number != NULL) {
  18. env->ReleaseStringUTFChars(number_str, number);
  19. }
  20. return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
  21. }

有关于HAL层的打电话实现,有兴趣的朋友可以去看 bt_hf_client.h




 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/264928
推荐阅读
相关标签
  

闽ICP备14008679号