在Settings的Bluetooth界面中,當用戶點擊當前的可連接設備時,系統會先對點擊的設備進行配對,在BluetoothSettings.java類中對應的源碼爲:
@Override
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
mLocalAdapter.stopScanning();
super.onDevicePreferenceClick(btPreference);
}
這是一個繼承至父類的方法,這裏首先會讓系統停止搜索藍牙設備,因爲當在配對的過程中,同時搜索的話會出現"“Couldn’t pair with **device because of an incorrect PIN or passkey"的錯誤。接下來會調用父類的onDevicePreferenceClick方法,
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
btPreference.onClicked();
}
這裏會進入BluetoothDevicePreference的onClicked方法,
void onClicked() {
int bondState = mCachedDevice.getBondState();
if (mCachedDevice.isConnected()) {
askDisconnect();
} else if (bondState == BluetoothDevice.BOND_BONDED) {
Xlog.d(TAG, mCachedDevice.getName() + " connect");
mCachedDevice.connect(true);
} else if (bondState == BluetoothDevice.BOND_NONE) {
pair();
}
}
這裏首先會獲取當前藍牙設備的狀態,如果是已經連接的話,就斷開連接;如果是已配對的話,就進行連接;如果是未配對的話,就進行配對,這裏我們進入到pair方法:
private void pair() {
if (!mCachedDevice.startPairing()) {
Utils.showError(getContext(), mCachedDevice.getName(),
R.string.bluetooth_pairing_error_message);
}
}
這裏通過CachedBluetoothDevice對象mCachedDevice調用startPairing方法,進去看看:
boolean startPairing() {
// Pairing is unreliable while scanning, so cancel discovery
if (mLocalAdapter.isDiscovering()) {
mLocalAdapter.cancelDiscovery();
}
if (!mDevice.createBond()) {
return false;
}
mConnectAfterPairing = true; // auto-connect after pairing
return true;
}
這裏首先就會再一次判斷當前系統是否是在搜索設備,如果是就取消搜索,接着就是調用BluetoothDevice對象mDevice的createBond方法:
public boolean createBond() {
if (sService == null) {
Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
return false;
}
try {
if (DBG) Log.d(TAG, "createBond: " + this);
return sService.createBond(this);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
這裏和搜索裏一樣,通過mService來調用createBond方法,這裏的mService其實就是AdapterService內部類AdapterServiceBinder的對象,
public boolean createBond(BluetoothDevice device) {
if (!Utils.checkCaller()) {
Log.e("dy","Utils.checkCaller()==false");
Log.w(TAG,"createBond(): not allowed for non-active user");
return false;
}
AdapterService service = getService();
if (service == null) return false;
return service.createBond(device);
}
這裏調用AdapterService類的createBond方法
boolean createBond(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
return false;
}
// Pairing is unreliable while scanning, so cancel discovery
// Note, remove this when native stack improves
cancelDiscoveryNative();
Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
msg.obj = device;
mBondStateMachine.sendMessage(msg);
return true;
}
這裏又會通過cancelDiscoveryNative這個本地方法來取消搜索,接着利用BondStateMachine 的 mBondStateMachine對象發送了一個配對的消息,消息是在BondStateMachine 中接收:
@Override
public boolean processMessage(Message msg) {
BluetoothDevice dev = (BluetoothDevice)msg.obj;
boolean result = false;
if (mDevices.contains(dev) &&
msg.what != CANCEL_BOND && msg.what != BONDING_STATE_CHANGE) {
deferMessage(msg);
return true;
}
switch (msg.what) {
case CREATE_BOND:
result = createBond(dev, false);
break;
case REMOVE_BOND:
result = removeBond(dev, false);
break;
case CANCEL_BOND:
result = cancelBond(dev);
break;
case BONDING_STATE_CHANGE:
int newState = msg.arg1;
int reason = getUnbondReasonFromHALCode(msg.arg2);
sendIntent(dev, newState, reason);
if(newState != BluetoothDevice.BOND_BONDING )
{
/* this is either none/bonded, remove and transition */
result = !mDevices.remove(dev);
if (mDevices.isEmpty()) {
// Whenever mDevices is empty, then we need to
// set result=false. Else, we will end up adding
// the device to the list again. This prevents us
// from pairing with a device that we just unpaired
result = false;
transitionTo(mStableState);
}
if (newState == BluetoothDevice.BOND_NONE)
{
// Set the profile Priorities to undefined
clearProfilePriorty(dev);
}
else if (newState == BluetoothDevice.BOND_BONDED)
{
// Restore the profile priorty settings
setProfilePriorty(dev);
}
}
else if(!mDevices.contains(dev))
result=true;
break;
default:
Log.e(TAG, "Received unhandled event:" + msg.what);
return false;
}
if (result) mDevices.add(dev);
return true;
}
}
當接收到的消息爲CREATE_BOND時,執行createBond方法:
private boolean createBond(BluetoothDevice dev, boolean transition) {
if (dev.getBondState() == BluetoothDevice.BOND_NONE) {
infoLog("Bond address is:" + dev);
byte[] addr = Utils.getBytesFromAddress(dev.getAddress());
if (!mAdapterService.createBondNative(addr)) {
sendIntent(dev, BluetoothDevice.BOND_NONE,
BluetoothDevice.UNBOND_REASON_REMOVED);
return false;
} else if (transition) {
transitionTo(mPendingCommandState);
}
return true;
}
return false;
}
這個方法有返回到AdapterService方法中調用它的createBondNative本地方法(之前在AdapterService中爲什麼不直接調用createBondNative呢?),接着我們在com_android_bluetooth_btservice_AdapterService中找到對應的jni方法:
static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address) {
ALOGV("%s:",__FUNCTION__);
jbyte *addr;
jboolean result = JNI_FALSE;
if (!sBluetoothInterface) return result;
addr = env->GetByteArrayElements(address, NULL);
if (addr == NULL) {
jniThrowIOException(env, EINVAL);
return result;
}
int ret = sBluetoothInterface->create_bond((bt_bdaddr_t *)addr);
env->ReleaseByteArrayElements(address, addr, 0);
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
這裏通過sBluetoothInterface來調用MTK藍牙相關庫的create_bond方法來實現配對,配對完畢後,會想上層回調配對的結果,
static void bond_state_changed_callback(bt_status_t status, bt_bdaddr_t *bd_addr,
bt_bond_state_t state) {
jbyteArray addr;
int i;
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
if (!bd_addr) {
ALOGE("Address is null in %s", __FUNCTION__);
return;
}
addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (addr == NULL) {
ALOGE("Address allocation failed in %s", __FUNCTION__);
return;
}
callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr);
callbackEnv->CallVoidMethod(sJniCallbacksObj, method_bondStateChangeCallback, (jint) status,
addr, (jint)state);
checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
callbackEnv->DeleteLocalRef(addr);
}
這裏會回調JniCallbacks的bondStateChangeCallback:
void bondStateChangeCallback(int status, byte[] address, int newState) {
mBondStateMachine.bondStateChangeCallback(status, address, newState);
}
這裏又要進入到BondStateMachine的bondStateChangeCallback方法中:
void bondStateChangeCallback(int status, byte[] address, int newState) {
BluetoothDevice device = mRemoteDevices.getDevice(address);
if (device == null) {
infoLog("No record of the device:" + device);
// This device will be added as part of the BONDING_STATE_CHANGE intent processing
// in sendIntent above
device = mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address));
}
infoLog("bondStateChangeCallback: Status: " + status + " Address: " + device
+ " newState: " + newState);
Message msg = obtainMessage(BONDING_STATE_CHANGE);
msg.obj = device;
if (newState == BOND_STATE_BONDED)
msg.arg1 = BluetoothDevice.BOND_BONDED;
else if (newState == BOND_STATE_BONDING)
msg.arg1 = BluetoothDevice.BOND_BONDING;
else
msg.arg1 = BluetoothDevice.BOND_NONE;
msg.arg2 = status;
sendMessage(msg);
}
這裏發送一個BONDING_STATE_CHANGE消息,
@Override
public boolean processMessage(Message msg) {
BluetoothDevice dev = (BluetoothDevice)msg.obj;
boolean result = false;
if (mDevices.contains(dev) &&
msg.what != CANCEL_BOND && msg.what != BONDING_STATE_CHANGE) {
deferMessage(msg);
return true;
}
switch (msg.what) {
case CREATE_BOND:
result = createBond(dev, false);
break;
case REMOVE_BOND:
result = removeBond(dev, false);
break;
case CANCEL_BOND:
result = cancelBond(dev);
break;
case BONDING_STATE_CHANGE:
int newState = msg.arg1;
int reason = getUnbondReasonFromHALCode(msg.arg2);
sendIntent(dev, newState, reason);
if(newState != BluetoothDevice.BOND_BONDING )
{
/* this is either none/bonded, remove and transition */
result = !mDevices.remove(dev);
if (mDevices.isEmpty()) {
// Whenever mDevices is empty, then we need to
// set result=false. Else, we will end up adding
// the device to the list again. This prevents us
// from pairing with a device that we just unpaired
result = false;
transitionTo(mStableState);
}
if (newState == BluetoothDevice.BOND_NONE)
{
// Set the profile Priorities to undefined
clearProfilePriorty(dev);
}
else if (newState == BluetoothDevice.BOND_BONDED)
{
// Restore the profile priorty settings
setProfilePriorty(dev);
}
}
else if(!mDevices.contains(dev))
result=true;
break;
default:
Log.e(TAG, "Received unhandled event:" + msg.what);
return false;
}
if (result) mDevices.add(dev);
return true;
}
程序會進入case BONDING_STATE_CHANGE:分支,這裏會對相應的配對結果作出相應的處理。
藍牙的配對就分析到這裏。