通过蓝牙获取通讯录及通话记录
路径:android-8.0.0_r1\frameworks\base\core\java\android\bluetooth
Pbap 协议:通过 Pbap(Phone Book Access Profile) 协议同步联系人/通话记录
BluetoothPbapClient.java:
该类是 @hide,可以通过修改源码重新编译,或者通过反射的方式获取此类的对象,,但应该是尚不成熟的,所以在此仅做简单学习用吧。
注:使用反射时,我的一加6手机发现该类的构造函数不存在,应该是被阉割了。在 Hikey970 板子上测试是ok的。
code:
// Create a BluetoothPbapClient proxy object.
BluetoothPbapClient(Context context, ServiceListener l) {
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if(mgr !=null) {
try{
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
}catch(RemoteException e) {
Log.e(TAG,"", e);
}
}
doBind();
}
// Upon successful connection to remote PBAP server the Client will attempt to automatically download the users phonebook and call log
publicbooleanconnect(BluetoothDevice device){
finalIBluetoothPbapClient service = mService;
if(service !=null&& isEnabled() && isValidDevice(device)) {
try{
returnservice.connect(device);
}catch(RemoteException e) {
Log.e(TAG, Log.getStackTraceString(newThrowable()));
returnfalse;
}
}
returnfalse;
}
蓝牙电话API调用
主要类:
BluetoothHeadsetClient.java 主要负责蓝牙通话的相关动作,比如接听等等
BluetoothHeadsetClientCall.java 主要负责蓝牙通话的状态,比如是来电还是去电等等。
HeadsetClientHalConstants.java 类里面只是定义了一些 int/boolean 类型的值。
HeadsetClientService.java 从名字就知道它是一个服务,里面还有一个BluetoothHeadsetClientBinder内部类,该内部类主要负责和 BluetoothHeadsetClient 进行跨进程通信。另外, HeadsetClientService 也是 BluetoothHeadsetClientBinder 和 HeadsetClientStateMachine 之间的桥梁。
HeadsetClientStateMachine 是一个状态机,即管理连接的状态也是通话时 java 和 C/C++ 之间的桥梁,通过 JNI 机制和 com_android_bluetooth_hfpclient 里面的方法互相调用。
com_android_bluetooth_hfpclient 蓝牙通话动作,拨号/接听/挂断/拒接 实际的执行者。
打电话
// 设置蓝牙电话客户端监听
bluetoothAdapter.getProfileProxy(MainActivity.this,newBluetoothProfile.ServiceListener() {
@Override
publicvoidonServiceConnected(intprofile, BluetoothProfile proxy){
// 连接后,拿到蓝牙电话客户端的代理 mHeadsetClient
// Api 接口: IBluetoothHeadsetClient.aidl
mHeadsetClient = (BluetoothHeadsetClient) proxy;
}
@Override
publicvoidonServiceDisconnected(intprofile){
}
}, BluetoothProfile.HEADSET);
// 给110打电话
mHeadsetClient.dial(mDevice,"110")
BluetoothHeadsetClient.java:
publicBluetoothHeadsetClientCalldial(BluetoothDevice device, String number){
finalIBluetoothHeadsetClient service = mService;
returnservice.dial(device, number);
}
// 当我们获取得到一个BluetoothHeadsetClient时,会调用 BluetoothHeadsetClient 的构造函数,它会执行一个doBind()
BluetoothHeadsetClient(Context context, ServiceListener l) {
doBind();
}
booleandoBind(){
Intent intent =newIntent(IBluetoothHeadsetClient.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(),0);
intent.setComponent(comp);
if(comp ==null|| !mContext.bindServiceAsUser(intent, mConnection,0, mContext.getUser())) {
returnfalse;
}
returntrue;
}
privatefinalServiceConnection mConnection =newServiceConnection() {
@Override
publicvoidonServiceConnected(ComponentName className, IBinder service){
// private volatile IBluetoothHeadsetClient mService;
mService = IBluetoothHeadsetClient.Stub.asInterface(Binder.allowBlocking(service));
mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT,
BluetoothHeadsetClient.this);
}
@Override
publicvoidonServiceDisconnected(ComponentName className){
}
};
// 获得一个IBluetoothHeadsetClient 对象时,系统会去绑定一个服务,并获取这个服务的代理,而这个服务才是真正实现打电话的地方
// 该服务的实现在立即实现: HeadsetClientService
HeadsetClientService.java:
BluetoothHeadsetClientCalldial(BluetoothDevice device, String number){
// 安卓中的状态机
HeadsetClientStateMachine sm = getStateMachine(device);
intconnectionState = sm.getConnectionState(device);
BluetoothHeadsetClientCall call =newBluetoothHeadsetClientCall(
device, HeadsetClientStateMachine.HF_ORIGINATED_CALL_ID,
BluetoothHeadsetClientCall.CALL_STATE_DIALING, number,false/* multiparty */,
true/* outgoing */);
Message msg = sm.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER);
msg.obj = call;
sm.sendMessage(msg);
returncall;
}
HeadsetClientStateMachine.java:
publicsynchronizedbooleanprocessMessage(Message message){
switch(message.what) {
caseDIAL_NUMBER:
// Add the call as an outgoing call.
BluetoothHeadsetClientCall c = (BluetoothHeadsetClientCall) message.obj;
mCalls.put(HF_ORIGINATED_CALL_ID, c);
// 最终实现打电话的方法是 dialNative(), 一个本地方法
// 接听拒接等同理
if(NativeInterface.dialNative(getByteAddress(mCurrentDevice), c.getNumber())) {
addQueuedAction(DIAL_NUMBER, c.getNumber());
// Start looping on calling current calls.
sendMessage(QUERY_CURRENT_CALLS);
}
break;
}
returnHANDLED;
}
接听电话
如果有来电,服务端手机接通电话或者对方挂断电话,我们怎么知道呢?这些都是 com_android_bluetooth_hfpclient.cpp 通过 JNI 机制调用通话状态机的方法 sendCallChangedIntent,将电话的状态(包含在 BluetoothHeadsetClientCall.java 中)通过广播发送出来,第三方apk监听状态就可以进行相应的操作了。
HeadsetClientStateMachine.java:
privatevoidsendCallChangedIntent(BluetoothHeadsetClientCall c){
Intent intent =newIntent(BluetoothHeadsetClient.ACTION_CALL_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(BluetoothHeadsetClient.EXTRA_CALL, c);
mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM);
}
网友评论