前情提要:
上一篇提到已經彈出 dialog 視窗詢問是否配對,
這裡會發現使用者在彈出視窗按下的事件中,
會發送一個帶有 BluetoothPeripheralHandover.ACTION_ALLOW_CONNECT
的 intent:
packages/apps/Nfc/src/com/android/nfc/handover/ConfirmConnectActivity.java
32 public class ConfirmConnectActivity extends Activity {
33 BluetoothDevice mDevice;
34 AlertDialog mAlert = null;
35 @Override
36 protected void onCreate(Bundle savedInstanceState) {
... ...
46 builder.setMessage(confirmString)
47 .setCancelable(false)
**//使用者按下YES按鈕後處理**
48 .setPositiveButton(res.getString(R.string.pair_yes),
49 new DialogInterface.OnClickListener() {
50 public void onClick(DialogInterface dialog, int id) {
51 Intent allowIntent = new Intent(**BluetoothPeripheralHandover.ACTION_ALLOW_CONNECT**);
52 allowIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
53 **sendBroadcast(allowIntent);**
54 ConfirmConnectActivity.this.mAlert = null;
55 ConfirmConnectActivity.this.finish();
56 }
57 })
**//使用者按下NO按鈕後處理**
58 .setNegativeButton(res.getString(R.string.pair_no),
59 new DialogInterface.OnClickListener() {
60 public void onClick(DialogInterface dialog, int id) {
61 Intent denyIntent = new Intent(BluetoothPeripheralHandover.ACTION_DENY_CONNECT);
62 denyIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
63 sendBroadcast(denyIntent);
64 ConfirmConnectActivity.this.mAlert = null;
65 ConfirmConnectActivity.this.finish();
66 }
67 });
6
然後再由先前的 handleIntent
接收處理:
packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
455 void handleIntent(Intent intent) {
456 String action = intent.getAction();
457 // Everything requires the device to match...
458 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
459 if (!mDevice.equals(device)) return;
460
461 if (**ACTION_ALLOW_CONNECT**.equals(action)) {
462 mHandler.removeMessages(MSG_TIMEOUT);
463 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TIMEOUT), TIMEOUT_MS);
464 **nextStepConnect();**
... ...
還記得嗎?剛剛 mState
切換成STATE_WAITING_FOR_BOND_CONFIRMATION
,呼叫 startBonding()
函式:
packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
334 void nextStepConnect() {
335 switch (mState) {
... ...
353 case **STATE_WAITING_FOR_BOND_CONFIRMATION**:
354 if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
355 **startBonding**();
356 break;
357 }
439 void startBonding() {
**//狀態切換為STATE_BONDING**
440 **mState = STATE_BONDING;**
441 if (mRetryCount == 0) {
442 toast(getToastString(R.string.pairing_peripheral));
443 }
444 if (mOobData != null) {
445 if (!mDevice.createBondOutOfBand(mTransport, mOobData)) {
446 toast(getToastString(R.string.pairing_peripheral_failed));
447 complete(false);
448 }
449 } else if (!mDevice.createBond(mTransport)) {
450 toast(getToastString(R.string.pairing_peripheral_failed));
451 complete(false);
452 }
453 }
無論我們配對成功與否,當配對狀態發生改變的時候,
就會走到前面說的 handleIntent
中對應的判斷。
藍芽端的 BluetoothDevice
就會發出 intent 中帶有目前 action 為 ACTION_BOND_STATE_CHANGED
,
並且此時的 mState 為 STATE_BONDING
:
455 void handleIntent(Intent intent) {
456 String action = intent.getAction();
... ...
467 } else if (BluetoothDevice.**ACTION_BOND_STATE_CHANGED**.equals(action)
468 && **mState == STATE_BONDING**) {
469 int bond = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
470 BluetoothAdapter.ERROR);
471 if (bond == BluetoothDevice.BOND_BONDED) {
472 mRetryCount = 0;
473 **nextStepConnect**();
查看上面代碼,在配對成功的時候調用 nextStepConnect()
;
失敗的時候根據判斷重試,或者直接做最後的賦值操作。
在 nextStepConnect()
當中此時的狀態為 STATE_BONDING
,
注意此時已經是配對成功了,但是 mState
還沒改變:
packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
334 void nextStepConnect() {
335 switch (mState) {
... ...
**//到這一步的時候已經配對完畢了,要對不同的profile進行不同的connect
//且會按照順序通過判斷依次進行鏈接**
359 **case STATE_BONDING:**
360 // Bluetooth Profile service will correctly serialize
361 // HFP then A2DP connect
**//狀態切換為STATE_CONNECTING**
362 **mState = STATE_CONNECTING;**
363 synchronized (mLock) {
364 if (mTransport == BluetoothDevice.TRANSPORT_LE) {
**//如果是HID設備(滑鼠)時**
365 if (mInput.getConnectionState(mDevice)
366 != BluetoothProfile.STATE_CONNECTED) {
367 mHidResult = RESULT_PENDING;
368 toast(getToastString(R.string.connecting_peripheral));
369 break;
370 } else {
371 **mHidResult = RESULT_CONNECTED**;
372 }
... ...
**//下面兩個Headset和A2DP的處理流程同上HID設備**
405 }
藍芽端會根據不同的 profile 調用不同的 connect 方式。
在連接成功後藍芽那邊會往外發送廣播,會被 handleIntent
進行處理,
此處我們是以鏈接藍牙滑鼠為例子,
那麼就會走到BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED
,
然後又去調用 nextStep()
又會走到 nextStepConnect()
。
但此時的狀態時為 STATE_CONNECTING
:
packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
... ...
**//當完成連接後,無論成功與否都會跑如下過程**
407 **case STATE_CONNECTING:**
408 if (mTransport == BluetoothDevice.TRANSPORT_LE) {
409 if (mHidResult == RESULT_PENDING) {
410 break;
411 } else if (mHidResult == RESULT_CONNECTED) {
412 toast(getToastString(R.string.connected_peripheral));
413 mDevice.setAlias(mName);
414 complete(true);
415 } else {
416 toast (getToastString(R.string.connect_peripheral_failed));
417 complete(false);
418 }
... ...
**//下面Headset和A2DP的處理流程同上HID設備**
435 break;
進入到對應的判斷中做最後的通知處理即可,調用complete。
這裡就差不多完成了,轉交到 BluetoothAdapter
中把 profile 關閉,
再呼叫回調完成的函數:packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
523 void complete(boolean connected) {
524 if (DBG) Log.d(TAG, "complete()");
525 mState = STATE_COMPLETE;
526 mContext.unregisterReceiver(mReceiver);
527 mHandler.removeMessages(MSG_TIMEOUT);
528 mHandler.removeMessages(MSG_RETRY);
529 synchronized (mLock) {
530 if (mA2dp != null) {
531 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dp);
532 }
533 if (mHeadset != null) {
534 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadset);
535 }
536
537 if (mInput != null) {
538 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HID_HOST, mInput);
539 }
540
541 mA2dp = null;
542 mHeadset = null;
543 mInput = null;
544 }
545 mCallback.onBluetoothPeripheralHandoverComplete(connected);
546 }
至此完成了類似於讀取 Tag 的分發流程,
把每個外設 (Peripheral) 都看成是一個 NFC 的 Tag。
是不是很有趣啊!哈哈哈!
所以目前我們透過 NFC 分發流程已經完成了藍芽連接,
下一篇我們會介紹 P2P 模式最後要透過藍芽傳輸的過程。