??
在之前晓东已经和大家分析完成了蓝牙打开和蓝牙搜索的过程了,在搜索到设备的下一步我们要做的就是蓝牙的配对了。本文晓东将和大家一起来看看蓝牙配对究竟涉及到了哪些内容。
1、UI上的点击设备开始
在android中,对设备的点击都是在onclicked函数中实现的,所以我们就从这个函数开始分析了:
//对对应设备点击之后的操作
void onClicked() {
int bondState = mCachedDevice.getBondState();
//若是该设备已经连接了,就断开连接
if (mCachedDevice.isConnected()) {
askDisconnect();
} else {
// Single link version, reject the second connect request
if (mLocalAdapter.isSingleLinkVersion() == true &&
mLocalAdapter.getAdapterConnectionState() != BluetoothAdapter.STATE_DISCONNECTED) {
Context context = getContext();
String toastMsg = context.getString(R.string.bluetooth_single_slave_pair_only_device);
Toast.makeText(getContext(), toastMsg, Toast.LENGTH_SHORT).show();
return;
}
//若是已经配对过了,就开始连接
if (bondState == BluetoothDevice.BOND_BONDED) {
mCachedDevice.connect(true);
//若是还没有配对,则开始配对
} else if (bondState == BluetoothDevice.BOND_NONE) {
pair();
}
}
}
所以,其实同样一个点击在设备处于不同状态下是有不同操作的,毫无疑问,最开始我们总是位于最初的状态,这个时候的点击就是开始配对了。我们去看看配对是怎么做的:
private void pair() {
//开始配对
if (!mCachedDevice.startPairing()) {
//配对出问题,显示error信息
Utils.showError(getContext(), mCachedDevice.getName(),
R.string.bluetooth_pairing_error_message);
}
}
调动的是startpairing函数来实现真正的配对操作:
boolean startPairing() {
// Pairing is unreliable while scanning, so cancel discovery
//若是正在扫描,就先cancel掉扫描操作
if (mLocalAdapter.isDiscovering()) {
mLocalAdapter.cancelDiscovery();
}
//开始配对,这就到framework层了
if (!mDevice.createBond()) {
return false;
}
//配对后自动连接
mConnectAfterPairing = true;// auto-connect after pairing
return true;
}
2、framework层的配对操作分析
上面的操作会真正调用下面这个framework的函数:
public synchronized boolean createBond(String address) {
//看是否可以配对?比如有没有设备正在配对之类
if (!isBondingFeasible(address)) return false;
//开始配对。timeout是1分钟,详细分析见4
if (!createPairedDeviceNative(address, 60000/*1 minute*/ )) {
return false;
}
//把这个地址赋值到pendingoutgonigbonding中
mBondState.setPendingOutgoingBonding(address);
//设置状态为bonding
mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
return true;
}
3、状态改变到bonding的分析
设置bond的状态
/*package*/ synchronized boolean setBondState(String address, int state) {
return setBondState(address, state, 0);
}
/*package*/ synchronized boolean setBondState(String address, int state, int reason) {
mBondState.setBondState(address.toUpperCase(), state, reason);
return true;
}
public synchronized void setBondState(String address, int state) {
setBondState(address, state, 0);
}
/** reason is ignored unless state == BOND_NOT_BONDED */
public synchronized void setBondState(String address, int state, int reason) {
if (DBG) Log.d(TAG, setBondState+ address ++ state + reason:+ reason);
//检查状态是否真的改变
int oldState = getBondState(address);
if (oldState == state) {
return;
}
// Check if this was an pending outgoing bonding.
// If yes, reset the state.
//看是不是从bonding的状态变化的,若是,则把mPendingOutgoingBonding位清空
if (oldState == BluetoothDevice.BOND_BONDING) {
if (address.equals(mPendingOutgoingBonding)) {
mPendingOutgoingBonding = null;
}
}
if (state == BluetoothDevice.BOND_BONDED) {
boolean setTrust = false;
if (mPairingRequestRcvd.contains(address)) setTrust = true;
mService.addProfileState(address, setTrust);
mPairingRequestRcvd.remove(address);
} else if (state == BluetoothDevice.BOND_BONDING) {
//若是bonding,则先得到a2dpproxy和headsetproxy,这个是为了后面的连接做准备的
if (mA2dpProxy == null || mHeadsetProxy == null) {
getProfileProxy();
}
} else if (state == BluetoothDevice.BOND_NONE) {
mPairingRequestRcvd.remove(address);
}
//主要是bonded和none的处理,我们暂时不看
setProfilePriorities(address, state);
if (DBG) {
Log.d(TAG, address +bond state+ oldState +->+ state
+( + reason + ));
}
3.1 getProfileProxy的分析
public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
int profile) {
if (context == null || listener == null) return false;
//新建对应profile
if (profile == BluetoothProfile.HEADSET) {
BluetoothHeadset headset = new BluetoothHeadset(context, listener);
return true;
} else if (profile == BluetoothProfile.A2DP) {
BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
return true;
} else if (profile == BluetoothProfile.INPUT_DEVICE) {
BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
return true;
} else if (profile == BluetoothProfile.PAN) {
BluetoothPan pan = new BluetoothPan(context, listener);
return true;
} else if (profile == BluetoothProfile.HEALTH) {
BluetoothHealth health = new BluetoothHealth(context, listener);
return true;
} else {
return false;
}
}
以a2dp为例,就是返回对应的类
/*package*/ BluetoothA2dp(Context mContext, ServiceListener l) {
IBinder b = ServiceManager.getService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE);
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter();
if (b != null) {
//得到对应的service
mService = IBluetoothA2dp.Stub.asInterface(b);
if (mServiceListener != null) {
//返回this
mServiceListener.onServiceConnected(BluetoothProfile.A2DP, this);
}
} else {
Log.w(TAG, Bluetooth A2DP service not available!);
// Instead of throwing an exception which prevents people from going
// into Wireless settings in the emulator. Let it crash later when it is actually used.
mService = null;
}
}