這算是有點番外篇的感覺,剛好前文提到 Handover。
因為一般文章比較常看到 NFC 啟動或感應流程,
好像蠻少看到 P2P 這部份的,
我想應該是和現在很少人會去使用這部份有關吧,
畢竟目前手機很少人會放大檔案。
你可能會很困惑藍芽滑鼠就用藍芽就好了,
幹麻還需要用到 NFC 功能?
那假設你配對的過程,
只要像你過捷運那樣「逼!」一下就配對成功,
是不是快到要吃手手了呢。(笑)
Android Beam 的流程其實也是配對透過 NFC,
但是實際上傳輸是透過 dispatcherTag
函式給藍芽。
之前提到會使用 Handover 的主要有兩種情況:
我們就以最簡單的帶有 NFC 功能的藍芽滑鼠作範例:
從 NFC 感應到這裡的流程請參考前文,dispatchTag
是負責收到消息的當下作分發,
看要分給藍芽或 WiFi 去作下一步。
packages/apps/Nfc/src/com/android/nfc/NfcDispatcher.java
276 public int dispatchTag(Tag tag) {
... ...
336 if (tryPeripheralHandover(message)) {
337 if (DBG) Log.i(TAG, "matched BT HANDOVER");
338 return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
339 }
... ...
668 public boolean tryPeripheralHandover(NdefMessage m) {
669 if (m == null || !mDeviceSupportsBluetooth) return false;
670
671 if (DBG) Log.d(TAG, "tryHandover(): " + m.toString());
672
//**下面這個方法mHandoverDataParser.parseBluetooth(m)方法是通過檢測到的Tag中攜帶的NDEF式的信息,**
//**信息包含了當前NFC設備(藍牙鼠標、鍵盤、耳機等)的各種設備信息。**
673 HandoverDataParser.BluetoothHandoverData handover = mHandoverDataParser.parseBluetooth(m);
674 if (handover == null || !handover.valid) return false;
675 if (UserManager.get(mContext).hasUserRestriction(
676 UserManager.DISALLOW_CONFIG_BLUETOOTH,
677 // hasUserRestriction does not support UserHandle.CURRENT
678 UserHandle.of(ActivityManager.getCurrentUser()))) {
679 return false;
680 }
681
//**下面就是解析完Tag中的NDEF攜帶的信息後,放到響應的變量中以便後續使用。**
682 Intent intent = new Intent(mContext, PeripheralHandoverService.class);
683 intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_DEVICE, handover.device);
684 intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_NAME, handover.name);
685 intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_TRANSPORT, handover.transport);
686 if (handover.oobData != null) {
687 intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_OOB_DATA, handover.oobData);
688 }
689 if (handover.uuids != null) {
690 intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_UUIDS, handover.uuids);
691 }
692 if (handover.btClass != null) {
693 intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_CLASS, handover.btClass);
694 }
695 intent.putExtra(PeripheralHandoverService.EXTRA_BT_ENABLED, mBluetoothEnabledByNfc.get());
696 intent.putExtra(PeripheralHandoverService.EXTRA_CLIENT, mMessenger);
//**啟動PeripheralHandoverService去進一步的處理。**
697 mContext.startServiceAsUser(intent, UserHandle.CURRENT);
698
699 return true;
700 }
接下來就是看 PeripheralHandoverService
中的 onCreate
以及 onStartCommand
構造:
packages/apps/Nfc//src/com/android/nfc/handover/PeripheralHandoverService.java
41 public class PeripheralHandoverService extends Service implements BluetoothPeripheralHandover.Callback {
... ...
110 @Override
111 public int onStartCommand(Intent intent, int flags, int startId) {
112
113 synchronized (sLock) {
114 if (mStartId != 0) {
115 mStartId = startId;
116 // already running
117 return START_STICKY;
118 }
119 mStartId = startId;
120 }
121
122 if (intent == null) {
123 if (DBG) Log.e(TAG, "Intent is null, can't do peripheral handover.");
124 stopSelf(startId);
125 return START_NOT_STICKY;
126 }
127
128 if (**doPeripheralHandover**(intent.getExtras())) {
129 return START_STICKY;
130 } else {
131 stopSelf(startId);
132 return START_NOT_STICKY;
133 }
134 }
135
136 @Override
137 public void onCreate() {
138 super.onCreate();
139 mNfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
140
141 IntentFilter filter = new IntentFilter(**BluetoothAdapter.ACTION_STATE_CHANGED**);
142 registerReceiver(mBluetoothStatusReceiver, filter);
143 }
上面我們需要關注的就是:
onCreate()
註冊的 BluetoothAdapter.ACTION_STATE_CHANGED
廣播。onStartCommand()
調用 doPeripheralHandover
去進一步的操作。 onCreate()
最後註冊的 mBluetoothStatusReceiver
如下:packages/apps/Nfc//src/com/android/nfc/handover/PeripheralHandoverService.java
91 final BroadcastReceiver mBluetoothStatusReceiver = new BroadcastReceiver() {
92 @Override
93 public void onReceive(Context context, Intent intent) {
94 String action = intent.getAction();
95 if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
96 handleBluetoothStateChanged(intent);
97 }
98 }
99 };
這個 BroadcastReceiver 的作用在藍牙打開,並且是由 NFC 打開的時候,
就進一步的調用 mBluetoothPeripheralHandover
相關的流程進行處理:packages/apps/Nfc//src/com/android/nfc/handover/PeripheralHandoverService.java
203 private void handleBluetoothStateChanged(Intent intent) {
204 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
205 BluetoothAdapter.ERROR);
206 if (state == BluetoothAdapter.STATE_ON) {
207 // If there is a pending device pairing, start it
208 if (mBluetoothPeripheralHandover != null &&
209 !mBluetoothPeripheralHandover.hasStarted()) {
210 if (!**mBluetoothPeripheralHandover.start()**) {
211 mNfcAdapter.resumePolling();
212 }
213 }
214 } else if (state == BluetoothAdapter.STATE_OFF) {
215 mBluetoothEnabledByNfc = false;
216 mBluetoothHeadsetConnected = false;
217 }
218 }
mBluetoothPeripheralHandover
的宣告都在 BluetoothPeripheralHandover,
不急,後面會在看到。先看一下第二部份的 doPeripheralHandover
如下:packages/apps/Nfc//src/com/android/nfc/handover/PeripheralHandoverService.java
151 boolean doPeripheralHandover(Bundle msgData) {
**//只能有一個BluetoothPeripheralHandover對象,處理這個的Nfc Tag信息讀取,
//此時想要再檢測就得把NFC設備的開關進行打開和關閉操作。**
152 if (mBluetoothPeripheralHandover != null) {
153 Log.d(TAG, "Ignoring pairing request, existing handover in progress.");
154 return true;
155 }
156
... ...
**//這塊就是把msgData中攜帶的數據取出來。(NDEF信息中的數據)**
177 mBluetoothEnabledByNfc = msgData.getBoolean(EXTRA_BT_ENABLED);
178
**//BluetoothPeripheralHandover是真正的處理的地方,此處進行唯一的實例化。
//傳入的參數大都是從NDEF信息中解析出來的。**
179 mBluetoothPeripheralHandover = new BluetoothPeripheralHandover(
180 this, mDevice, name, transport, oobData, uuids, btClass, this);
181
... ...
**//如果藍牙已經打開,直接調用start()去進行配對等的處理。**
186 if (mBluetoothAdapter.isEnabled()) {
187 if (!**mBluetoothPeripheralHandover.start()**) {
188 mHandler.removeMessages(MSG_PAUSE_POLLING);
189 mNfcAdapter.resumePolling();
190 }
**//如果藍牙沒有打開那麼就調用enableBluetooth去打開藍牙設備。
//此處你打開藍牙成功後也會往外發送廣播最終到前面的receiver中最後也是調用start進行了處理。**
191 } else {
192 // Once BT is enabled, the headset pairing will be started
193 if (!enableBluetooth()) {
194 Log.e(TAG, "Error enabling Bluetooth.");
195 mBluetoothPeripheralHandover = null;
196 return false;
197 }
198 }
199
200 return true;
201 }
**//此處調用的是framework專門為system級別的app設定的方法enableNoAutoConnect,
//這個方法打開藍牙後不會記錄此次操作。**
251 boolean enableBluetooth() {
252 if (!mBluetoothAdapter.isEnabled()) {
253 mBluetoothEnabledByNfc = true;
254 return mBluetoothAdapter.enableNoAutoConnect();
255 }
256 return true;
257 }
我們會發現,
上面的兩種情況不管哪一個,
最終都走到了 BluetoothPeripheralHandover
的 start()
方法,
接下來我們就在下一篇詳細說明吧。
https://blog.csdn.net/zy00000000001/article/details/73730458