Package/apps/Phone
BluetoothHandsfree.java
BluetoothHeadsetService.java
BluetoothAtPhonebook.java
BluetoothCmeError.java
Ø Package/apps/settings/Bluetooth
HeadsetProfile.java
Ø Framework/base/core/java/android/Bluetooth
HeadsetBase.java
BluetoothHeadset.java
Android 实现了对Headset和Handsfree 两种profile的支持。其实现核心是BluetoothHeadsetService,在PhoneApp创建的时候会通过startService()启动它。
电话应用启动时(PhoneApp的onCreate里),就会启动HSP服务
if (BluetoothAdapter.getDefaultAdapter() != null) {
// Start BluetoothHandsree even if device is not voice capable.
mBtHandsfree = BluetoothHandsfree.init(this, mCM);
startService(new Intent(this, BluetoothHeadsetService.class));
}
BluetoothHeadsetService的onStart里,判断蓝牙是否可用(Return true if Bluetooth is currently enabled and ready for use),然后就切换到蓝牙通道
if (mAdapter.isEnabled()) {
mAg.start(mIncomingConnectionHandler);
mBtHandsfree.onBluetoothEnabled();
}
if 语句里共有两句话,两句话的作用分别是:
第一句:连接
第二句:切换到蓝牙通道
BluetoothHeadsetService启动后即会进行HSP/HFP的判断,并且会接收不同的广播,来连接和切换通道,断开连接和断开蓝牙通道
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
switch (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.ERROR)) {
caseBluetoothAdapter.STATE_ON:
mAg.start(mIncomingConnectionHandler);
mBtHandsfree.onBluetoothEnabled();
break;
caseBluetoothAdapter.STATE_TURNING_OFF:
mBtHandsfree.onBluetoothDisabled();
mAg.stop();
if (currDevice != null) {
setState(currDevice, BluetoothHeadset.STATE_DISCONNECTED);
}
}
第一句是一个BluetoothAudioGateway mAg,在它的start里,检查headset, hands free的通道连接状况,并通过Handler 发出MSG_INCOMING_HANDSFREE_CONNECTION 和 MSG_INCOMING_HEADSET_CONNECTION的消息,之后的处理notifyIncomingConnection,使远端蓝牙设备连接进来。
notifyIncomingConnection调用到BluetoothService里,并发送了一个消息,这个消息发送到了BluetoothDeviceProfileState里,在这里面实现了蓝牙的连接, 且这里的连接方式同A2DP的连接是类似的,在BluetoothDeviceProfileState里实现mHeadsetService.connectHeadsetInternal()。
BluetoothService( notifyIncomingConnection () )---->
BluetoothDeviceProfileState( mHeadsetService.connectHeadsetInternal() )
这里面通过状态机,一系列复杂的流程之后,最终调用的是
BluetoothHeadsetService(connectHeadsetInternal())
onBluetoothEnabled 有两处调用,除了BluetoothHeadsetService的onstart(),mBluetoothReceiver也实现了切换蓝牙通道,我们看下另一处mBluetoothReceiver,这里是当接收到BluetoothAdapter.ACTION_STATE_CHANGED广播,状态是BluetoothAdapter.STATE_ON的状态时,也会切换到蓝牙通道。
切换蓝牙通道时,会有对A2DP的开和关的控制,调用的是audioOn()和 audioOff()
最终调用的是BluetoothA2dp里的suspendSink()和 resumeSink()。
audioOn()时,会发送一个消息MESSAGE_CHECK_PENDING_SCO给HandsfreeMessageHandler,它的处理如下:
图3 audioOn
这里有个connectScoThread(),我们一步步跟下去会发现它其它建立了一个SCO连接。
连接成功后会调用setBluetoothScoOn(),切换到蓝牙通道。
图4 connectSco
onBluetoothEnabled()---->
IncomingScoAcceptThread.java---->
connectSco()---->
setBluetoothScoOn(true)
Ø frameworks\base\core\java\android\bluetooth
IBluetoothA2dp.aidl
BluetoothA2dp.java
Ø packages\apps\Settings\src\com\android\settings\bluetooth
A2dpProfile.java
Ø frameworks\base\core\java\android\server
BluetoothA2dpService.java
Ø frameworks\base\core\jni
android_server_ BluetoothA2dpService.cpp
BluetoothDevicePreference( onClick() / connect() )配对
CachedBluetoothDevice.connect()---->
CachedBluetoothDevice. connectWithoutResettingTimer()---->
connectInt()---->
profile.connect(mDevice)
这时的profile是LocalBluetoothProfile ,由其子类A2DProfile实现connect方法
A2dpProfile( connect() ) ---->
BluetoothA2DP( connect() ) ---->
BluetoothA2DPService( connect() ) ---->
BluetoothService( connectSink() ) ---->
BluetoothProfileState( dispatchMessage() )---->
BluetoothDeviceProfileState( mA2dpService.connectSinkInternal(mDevice) )
这里面通个状态机,一系列复杂的流程之后,最终调用的是
BluetoothA2dpService( connectSinkInternal())
这里的状态,简要描述一下:
BluetoothService.java里
Code:
public boolean connectSink(String address) {
if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
if (state != null) {
Message msg = new Message();
msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
msg.obj = state;
mA2dpProfileState.sendMessage(msg);
return true;
}
return false;
}
这里主要是发送了一个消息BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING
这个消息的处理是在BluetoothProfileState.java里,进入BluetoothProfileState后,发现跟BluetoothAdapterStateMachine一样,也是用到了状态机的模式,那么,是在哪个状态里处理了这个消息呢?我们看它的构造函数,
addState(mStableState);
addState(mPendingCommandState);
setInitialState(mStableState);
说明它的初始状态是mStableState,由此进一步分,它会走到StableState.java里的Enter(),然后走dispatchMessage(), 而在dispatchMessage()里
private void dispatchMessage(Message msg) {
BluetoothDeviceProfileState deviceProfileMgr = (BluetoothDeviceProfileState)msg.obj;
int cmd = msg.arg1;
if (mPendingDevice == null || mPendingDevice.equals(deviceProfileMgr.getDevice())) {
mPendingDevice = deviceProfileMgr.getDevice();
deviceProfileMgr.sendMessage(cmd);
} else {
Message deferMsg = new Message();
deferMsg.arg1 = cmd;
deferMsg.obj = deviceProfileMgr;
deferMessage(deferMsg);
}
}
最终又通过deferMessage,调用到BluetoothDeviceProfileState里去处理这个消息,上面绕了这么大一个圈子,只说明了一件事,CONNECT_A2DP_OUTGOING,这个消息,经过层层封装,最张交由BluetoothDeviceProfileState去处理,最终在processCommand方法,处理了这个消息
case CONNECT_A2DP_OUTGOING:
if (mA2dpService != null) {
return mA2dpService.connectSinkInternal(mDevice);
}
break;
可以看到,connectSink()实现调用的是connectSinkInternal()方法,从而进一步经JNI,调到Bluez里。