赞
踩
前段时间做车机蓝牙电话的项目,接触到了部分关于蓝牙电话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。
常用的接口有
- boolean acceptCall(in BluetoothDevice device, int flag);
- boolean holdCall(in BluetoothDevice device);
- boolean rejectCall(in BluetoothDevice device);
- 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,
- public boolean dial(BluetoothDevice device, String number) {
- if (DBG) log("dial()");
- if (mService != null && isEnabled() &&
- isValidDevice(device)) {
- try {
- return mService.dial(device, number);
- } catch (RemoteException e) {
- Log.e(TAG, Log.getStackTraceString(new Throwable()));
- }
- }
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
- }
我们发现,实现打电话功能函数是dial,而真正实现打电话的是mService.dial(device, number); 这个mService的定义
private IBluetoothHeadsetClient mService;
当我们获取得到一个BluetoothHeadsetClient时,会调用
BluetoothHeadsetClient的构造函数,它会执行一个doBind(),
- boolean doBind() {
- Intent intent = new Intent(IBluetoothHeadsetClient.class.getName());
- ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
- intent.setComponent(comp);
- if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- android.os.Process.myUserHandle())) {
- Log.e(TAG, "Could not bind to Bluetooth Headset Client Service with " + intent);
- return false;
- }
- return true;
- }
当绑定服务成功时,mService 被赋值
- private ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName className, IBinder service) {
- mService = IBluetoothHeadsetClient.Stub.asInterface(service);
}
-
- @Override
- public void onServiceDisconnected(ComponentName className) { }
- };
原来我们获得一个IBluetoothHeadsetClient 对象时,系统会去绑定一个服务,并获取这个服务的代理,而这个服务才是真正实现打电话的地方。
这个服务实现是在packages/apps/Bluetooth/src/com/android/bluetooth/hfpclient/HeadsetClientService
.java, 绑定的服务是个内部类BluetoothHeadsetClientBinder
它调用了
- boolean dial(BluetoothDevice device, String number) {
- enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- int connectionState = mStateMachine.getConnectionState(device);
- if (connectionState != BluetoothProfile.STATE_CONNECTED &&
- connectionState != BluetoothProfile.STATE_CONNECTING) {
- return false;
- }
-
- Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER);
- msg.obj = number;
- mStateMachine.sendMessage(msg);
- return true;
- }
仔细一看,怎么又冒出个
mStateMachine,这是安卓中的状态机,我们跟进到HeadsetClientStateMachine.java文件中去。
当mStateMachine将信息发出(
mStateMachine.sendMessage(msg)
),此时蓝牙电话状态机状态为Connected ,进入processMessage
流程分支- case DIAL_NUMBER:
- if (dialNative((String) message.obj)) {
- addQueuedAction(DIAL_NUMBER, message.obj);
- } else {
- Log.e(TAG, "ERROR: Cannot dial with a given number:" + (String) message.obj);
- }
- break;
我们终于发现,实现打电话的方法是dialNative, 一个本地方法。
- static jboolean dialNative(JNIEnv *env, jobject object, jstring number_str) {
- bt_status_t status;
- const char *number = NULL;
- if (!sBluetoothHfpClientInterface) return JNI_FALSE;
-
- if (number_str != NULL) {
- number = env->GetStringUTFChars(number_str, NULL);
- }
-
- if (number != NULL) {
- if ( (status = sBluetoothHfpClientInterface->dial(number)) != BT_STATUS_SUCCESS) {
- ALOGE("Failed to dial, status: %d", status);
- }
- } else {
- if ( (status = sBluetoothHfpClientInterface->dial("")) != BT_STATUS_SUCCESS) {
- ALOGE("Failed to dial, status: %d", status);
- }
- }
-
- if (number != NULL) {
- env->ReleaseStringUTFChars(number_str, number);
- }
- return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
- }
有关于HAL层的打电话实现,有兴趣的朋友可以去看
bt_hf_client.h
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。