藍芽(二)藍芽搜尋、配對、連線
1.搜尋
從上一節我們可以知道,藍芽狀態發生了改變,併發生了回撥。咱們就從回撥開始。
DevicePickerFragment.java 用於藍芽設定介面的藍芽配置和管理
@Override
public void onBluetoothStateChanged(int bluetoothState) {
super.onBluetoothStateChanged(bluetoothState);
if (bluetoothState == BluetoothAdapter.STATE_ON) {
mLocalAdapter.startScanning(false);
}
}
最終會回撥到這個地方,具體怎麼回撥到這的暫時沒去分析,我猜測應該是回撥到這,如果有知道請不吝賜教。
好了,藍芽搜尋開始了
LocalBluetoothAdapter.java
public void startScanning(boolean force) {
// Only start if we're not already scanning
if (!mAdapter.isDiscovering()) {
if (!force) {
// Don't scan more than frequently than SCAN_EXPIRATION_MS,
// unless forced
if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
return;
}
// If we are playing music, don't scan unless forced.
A2dpProfile a2dp = mProfileManager.getA2dpProfile();
if (a2dp != null && a2dp.isA2dpPlaying()) {
return;
}
}
if (mAdapter.startDiscovery() ) {
mLastScan = System.currentTimeMillis();
}
}
下面會調到BluetoothAdapter.startDiscovery()==>AdapterService.startDiscovery()==>AS.startDiscoveryNative()==>JNI裡面的startDiscoveryNative()==>再下面就到hw裡面和bluetooth.start_discovery(void),這些暫時就不分析了,有興趣的可以自行分析。
2.連線/斷開/配對/取消配對
還是從藍芽設定介面講起吧,當點選設定介面的某個藍芽裝置時會回撥到DeviceListPreferenceFragment裡面
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
if (KEY_BT_SCAN.equals(preference.getKey())) {
mLocalAdapter.startScanning(true);
return true;
}
if (preference instanceof BluetoothDevicePreference) {
BluetoothDevicePreference btPreference = (BluetoothDevicePreference) preference;
CachedBluetoothDevice device = btPreference.getCachedDevice();
mSelectedDevice = device.getDevice();
onDevicePreferenceClick(btPreference);
return true;
}
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
btPreference.onClicked();
}
==》 void onClicked() {
int bondState = mCachedDevice.getBondState();
if (mCachedDevice.isConnected()) {
askDisconnect();
} else if (bondState == BluetoothDevice.BOND_BONDED) {
mCachedDevice.connect(true);
} else if (bondState == BluetoothDevice.BOND_NONE) {
pair();
}
}
上面的邏輯裡會根據不同的情況執行不同的邏輯,一目瞭然。
1)配對
private void pair() {
if (!mCachedDevice.startPairing()) {
Utils.showError(getContext(), mCachedDevice.getName(),
R.string.bluetooth_pairing_error_message);
}
注意了,開始拉紅線配對了。配對之前,如果有已婚的,那麼不好意思,必須拆開重新選擇物件了
public 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.createBond()==>adapterservice.createBond()==>adapterservice.createBond()==>向狀態機發送繫結訊息==》BondStateMachine.createBond()==>AdapterService.createBondNative()==>JNI==>hw==>external,想了解的自行分析。借用一下圖
配對完成之後,要幹嘛?大家都是正經人,所以要去結婚然後再去開房了。所以當配對成功之後,肯定有一個事件提供給上面BluetoothEventManager
,接收到bond完成事件
private class BondStateChangedHandler implements Handler {
259 public void onReceive(Context context, Intent intent,
260 BluetoothDevice device) {
261 if (device == null) {
262 Log.e(TAG, "ACTION_BOND_STATE_CHANGED with no EXTRA_DEVICE");
263 return;
264 }
265 int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
266 BluetoothDevice.ERROR);
267 CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
268 if (cachedDevice == null) {
269 Log.w(TAG, "CachedBluetoothDevice for device " + device +
270 " not found, calling readPairedDevices().");
271 if (!readPairedDevices()) {
272 Log.e(TAG, "Got bonding state changed for " + device +
273 ", but we have no record of that device.");
274 return;
275 }
276 cachedDevice = mDeviceManager.findDevice(device);
277 if (cachedDevice == null) {
278 Log.e(TAG, "Got bonding state changed for " + device +
279 ", but device not added in cache.");
280 return;
281 }
282 }
283
284 synchronized (mCallbacks) {
285 for (BluetoothCallback callback : mCallbacks) {
286 callback.onDeviceBondStateChanged(cachedDevice, bondState);
287 }
288 }
289 cachedDevice.onBondingStateChanged(bondState);
290
291 if (bondState == BluetoothDevice.BOND_NONE) {
292 int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
293 BluetoothDevice.ERROR);
294
295 showUnbondMessage(context, cachedDevice.getName(), reason);
296 }
297 }
void onBondingStateChanged(int bondState) {
if (bondState == BluetoothDevice.BOND_NONE) {
mProfiles.clear();
mConnectAfterPairing = false; // cancel auto-connect
setPhonebookPermissionChoice(ACCESS_UNKNOWN);
setMessagePermissionChoice(ACCESS_UNKNOWN);
setSimPermissionChoice(ACCESS_UNKNOWN);
mMessageRejectionCount = 0;
saveMessageRejectionCount();
}
refresh();
if (bondState == BluetoothDevice.BOND_BONDED) {
if (mDevice.isBluetoothDock()) {
onBondingDockConnect();
} else if (mConnectAfterPairing) {
connect(false);
}
mConnectAfterPairing = false;
}
請大家自己跟蹤一下,下面我省略了一些邏輯。接下來會走到
synchronized void connectInt(LocalBluetoothProfile profile) {
if (!ensurePaired()) {
return;
}
if (profile.connect(mDevice)) {
if (Utils.D) {
Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
}
return;
}
Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
}
具體connect的藍芽功能是什麼就會通過相關的協議進行連線。2)取消配對過程
與配對過程類似
3、連線與取消連線
1) 連線過程
2) 取消連線過程
和連線過程類似,略。
4、掃描
A、通過呼叫BluetoothAdapter的startDiscovery()方法告訴底層開始搜尋;
B、底層發廣播通知應用找到裝置或者掃描狀態變化,從而更新ui。