1. 程式人生 > >藍芽(二)藍芽搜尋、配對、連線

藍芽(二)藍芽搜尋、配對、連線

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。