在之前曉東已經和大家分析完成了藍牙打開和藍牙搜索的過程了,在搜索到設備的下一步我們要做的就是藍牙的配對了。本文曉東將和大家一起來看看藍牙配對究竟涉及到了哪些內容。
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;
}
}
所以,總得來說在jni之上,配對並沒有做太多的東西,就是調用對應的配對的jni之下的函數。
若您覺得該文章對您有幫助,請在下面用鼠標輕輕按一下“頂”,哈哈~~·