美文网首页
2020-07-08蓝牙电话apk的实现及源码分析(2)

2020-07-08蓝牙电话apk的实现及源码分析(2)

作者: fjasmin | 来源:发表于2020-07-08 22:52 被阅读0次


通过蓝牙获取通讯录及通话记录

路径: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);

}

相关文章

网友评论

      本文标题:2020-07-08蓝牙电话apk的实现及源码分析(2)

      本文链接:https://www.haomeiwen.com/subject/vehkcktx.html