前情提要:
先前提到 PeripheralHandoverService
不管走兩條路的哪一條,
onCreate()
註冊的 BluetoothAdapter.ACTION_STATE_CHANGED
廣播。onStartCommand()
調用 doPeripheralHandover
去進一步的操作。 最後都會通到 BluetoothPeripheralHandover
的 start()
,
下面可以看到我們最後的 mAction 是 ACTION_INIT
:
packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
153 /**
154 * Main entry point. This method is usually called after construction,
155 * to begin the BT sequence. Must be called on Main thread.
156 */
157 public boolean start() {
158 checkMainThread();
159 if (mState != STATE_INIT || mBluetoothAdapter == null
160 || (mProvisioning && mTransport != BluetoothDevice.TRANSPORT_LE)) {
161 return false;
162 }
163
164
165 IntentFilter filter = new IntentFilter();
166 filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
167 filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
168 filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
169 filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
170 filter.addAction(BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
171 filter.addAction(ACTION_ALLOW_CONNECT);
172 filter.addAction(ACTION_DENY_CONNECT);
173
174 mContext.registerReceiver(mReceiver, filter);
175
176 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TIMEOUT), TIMEOUT_MS);
177
178 **mAction = ACTION_INIT;**
179 mRetryCount = 0;
180
181 **nextStep();**
182
183 return true;
184 }
這個 nextStep()
很關鍵,後面會很常用到。
它會根據當前所處不同的 action 來選擇我們下一步要執行的動作。
此時我們處於最一開始的 ACTION_INIT
,所以走到 nextStepInit()
:packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
186 /**
187 * Called to execute next step in state machine
188 */
189 void nextStep() {
190 if (mAction == ACTION_INIT) {
191 **nextStepInit();**
192 } else if (mAction == ACTION_CONNECT) {
193 nextStepConnect();
194 } else {
195 nextStepDisconnect();
196 }
197 }
因為是第一次執行,所以 mState 就是 STATE_INIT
:
packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
199 /*
200 * Enables bluetooth and gets the profile proxies
201 */
202 void nextStepInit() {
203 switch (mState) {
**//只要其中一個不為null,就去getProfileProxys函式且狀態改為STATE_WAITING_FOR_PROXIES**
204 case STATE_INIT:
205 if (mA2dp == null || mHeadset == null || mInput == null) {
206 mState = STATE_WAITING_FOR_PROXIES;
207 if (!getProfileProxys()) {
208 complete(false);
209 }
210 break;
211 }
... ...
至此我們應該先分析一下 getProfileProxys()
如下,
很簡單的實現,就是調用了藍牙提供的接口去獲得對應的 profile:packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
318 boolean getProfileProxys() {
319
320 if (mTransport == BluetoothDevice.TRANSPORT_LE) {
321 if (!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.HID_HOST))
322 return false;
323 } else {
324 if(!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.HEADSET))
325 return false;
326
327 if(!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.A2DP))
328 return false;
329 }
330
331 return true;
332 }
注意 BluetoothPeripheralHandover implements BluetoothProfile.ServiceListener
,
所以在你連接到對應的 profile 會回調相關的接口 onServiceConnected
。
當成功鏈接的時候,會走如下的回調,然後實現具體的 profile 對象的實例化:packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
658 @Override
659 public void onServiceConnected(int profile, BluetoothProfile proxy) {
660 synchronized (mLock) {
661 switch (profile) {
662 case BluetoothProfile.HEADSET:
663 mHeadset = (BluetoothHeadset) proxy;
664 if (mA2dp != null) {
665 mHandler.sendEmptyMessage(MSG_NEXT_STEP);
666 }
667 break;
668 case BluetoothProfile.A2DP:
669 mA2dp = (BluetoothA2dp) proxy;
670 if (mHeadset != null) {
671 mHandler.sendEmptyMessage(MSG_NEXT_STEP);
672 }
673 break;
674 case BluetoothProfile.HID_HOST:
675 mInput = (BluetoothHidHost) proxy;
676 if (mInput != null) {
677 mHandler.sendEmptyMessage(MSG_NEXT_STEP);
678 }
679 break;
680 }
681 }
682 }
並且在實例化完畢後會,往外發送 MSG_NEXT_STEP
信息。
這個信息被如下 Handler 處理。packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
601 final Handler mHandler = new Handler() {
602 @Override
603 public void handleMessage(Message msg) {
604 switch (msg.what) {
605 case MSG_TIMEOUT:
... ...
**//可以看到重新調用了nextStep**
628 case MSG_NEXT_STEP:
629 nextStep();
630 break;
631 case MSG_RETRY:
... ...
641 }
642 }
643 };
注意此時 mAction
還是 ACTION_INIT
,
但 mState
已經變成 STATE_WAITING_FOR_PROXIES
。
所以會調用到 nextStepInit
中的 STATE_WAITING_FOR_PROXIES
這個選項當中:
packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
199 /*
200 * Enables bluetooth and gets the profile proxies
201 */
202 void nextStepInit() {
203 switch (mState) {
... ...
212 // fall-through
**//走到此處的時候證明已經獲得了需要連接的藍牙的對應協議的profile對應的service的實現**
213 **case STATE_WAITING_FOR_PROXIES:**
**//注意state此時變成了STATE_INIT_COMPLETE**
214 **mState = STATE_INIT_COMPLETE;**
215 // Check connected devices and see if we need to disconnect
216 synchronized(mLock) {
217 if (mTransport == BluetoothDevice.TRANSPORT_LE) {
**//處理HID裝置(滑鼠、鍵盤)的部份,根據目前連接與否來決定下一個的action
//這時候已連接裝置不包含目前這個,所以mAction切換成ACTION_CONNECT**
218 if (mInput.getConnectedDevices().contains(mDevice)) {
219 Log.i(TAG, "ACTION_DISCONNECT addr=" + mDevice + " name=" + mName);
220 mAction = ACTION_DISCONNECT;
221 } else {
222 Log.i(TAG, "ACTION_CONNECT addr=" + mDevice + " name=" + mName);
223 **mAction = ACTION_CONNECT;**
224 }
225 } else {
**//處理A2DP和HeadSet的部份,內容同上**
... ...
246 }
247 }
248 **nextStep();**
249 }
250
251 }
此時 mAction
切換為 ACTION_CONNECT
,
因此來分析上面提到很關鍵的 nextStep()
對應的方法 nextStepConnect()
:packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
334 void nextStepConnect() {
335 switch (mState) {
**//此時的state是STATE_INIT_COMPLETE走到如下:**
336 case STATE_INIT_COMPLETE:
337
**//如果未配對就會去調用requestPairConfirmation
//狀態切換為STATE_WAITING_FOR_BOND_CONFIRMATION**
338 if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
339 **requestPairConfirmation();**
340 **mState = STATE_WAITING_FOR_BOND_CONFIRMATION;**
341 break;
342 }
343
... ...
這時候要求配對會跳出一個 dialog 視窗詢問使用者,
發一個 intent 將藍芽參數丟給 ConfirmConnectActivity
處理:
packages/apps/Nfc/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
564 void requestPairConfirmation() {
565 Intent dialogIntent = new Intent(mContext, **ConfirmConnectActivity**.class);
566 dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
567 dialogIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
568 dialogIntent.putExtra(BluetoothDevice.EXTRA_NAME, mName);
569
570 mContext.startActivity(dialogIntent);
571 }
下一篇藍芽配對完後就完成所有的初始化流程了。