1. 程式人生 > >Bluetooth 藍芽開啟流程

Bluetooth 藍芽開啟流程

藍芽的開啟連線主要流程:

開啟
檢測
掃描
連線

一、開啟(開啟藍芽BT Turn on Turn off)
(藍芽的on/off由類BluetoothEnabler控制。)

開啟過程涉及到的類:
BluetoothEnabler(on/off的控制介面,介面的點選和狀態文字的顯示)
BluetoothService(最主要的類,開啟具體命令的執行緒進行enable,disable等操作)
LocalBluetoothManager(本機藍芽裝置管理,開啟關閉,搜尋等等,初始化BluetoothAdapter)
BluetoothAdapter(framework封裝的類,提供本地藍芽裝置的配置,包括開啟藍芽,搜尋周圍藍芽裝置,設定本地藍芽可見性;建立LocalBluetoothManager和BluetoothService的對映關係,主要是通過它呼叫BluetoothService的函式)
BluetoothEventRedirector(接收Bluetooth API 的廣播和回撥,並且將Settings中的UI執行緒上的事件分派到正確的類)

以下是結合google原生6.0程式碼作的簡要分析

  1. /packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothEnabler.java

BluetoothEnabler.java裡面的函式onSwitchChanged(Switch switchView, boolean isChecked)監聽on/off的變化,通過mLocalAdapter.setBluetoothEnabled(isChecked);設定下去。

   @Override
179    public void onSwitchChanged(Switch switchView, boolean isChecked) {
180
// Show toast message if Bluetooth is not allowed in airplane mode 181 if (isChecked && 182 !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) { 183 Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show
(); 184 // Reset switch to off 185 switchView.setChecked(false); 186 } 187 188 MetricsLogger.action(mContext, MetricsLogger.ACTION_BLUETOOTH_TOGGLE, isChecked); 189 190 if (mLocalAdapter != null) { 191 mLocalAdapter.setBluetoothEnabled(isChecked); 192 } 193 mSwitch.setEnabled(false); 194 }

2.開啟(關閉)操作成功後會有一個非同步事件ACTION_STATE_CHANGED返回,非同步事件由類BluetoothEventRedirector控制(接收廣播,進行處理)。在收到ACTION_STATE_CHANGED非同步事件後,還需要做update本地裝置profile的事情,讀取上次關閉前搜尋到的藍芽裝置。
(1) ACTION_STATE_CHANGED: 定義在/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java中。
(2)通過LocalBluetoothManager.setBluetoothStateInt(int state)方法調到 CachedBluetoothDeviceManager.onBluetoothStateChanged方法來讀取上次關閉之前搜尋到device.

   public synchronized void onBluetoothStateChanged(int bluetoothState) {
153        // When Bluetooth is turning off, we need to clear the non-bonded devices
154        // Otherwise, they end up showing up on the next BT enable
155        if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
156            for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
157                CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
158                if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
159                    cachedDevice.setVisible(false);
160                    mCachedDevices.remove(i);
161                } else {
162                    // For bonded devices, we need to clear the connection status so that
163                    // when BT is enabled next time, device connection status shall be retrieved
164                    // by making a binder call.
165                    cachedDevice.clearProfileConnectionState();
166                }
167            }
168        }
169    }

(3)來開啟EnableThread執行緒,進行開啟操作,藍芽的開啟關閉屬於非同步操作。
注意:
在啟動藍芽的時候,要注意的地方是不能正常啟動藍芽的情況,因為正常啟動的時候會返回BluetoothIntent.ENABLED_ACTION 這個Intent,當時當啟動出現異常的時候是沒有Intent返回的,android使用回撥函式來解決這個問題。

二、是否可檢測性(Discoverable)

藍芽模式有兩種模式:
SCAN_MODE_CONNECTABLE_DISCOVERABLE(可連線可發現)
SCAN_MODE_CONNECTABLE(可連線但不可發現)

藍芽的discoverable mode由/packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java控制,

128    public boolean onPreferenceClick(Preference preference) {
129        // toggle discoverability
130        mDiscoverable = !mDiscoverable;
131        setEnabled(mDiscoverable);
132        return true;
133    }

通過onPreferenceClick()方法,呼叫setEnabled(mDiscoverable);,然後呼叫到BluetoothAdapter.java裡面的setScanMode () 方法

1133    /** @hide */
1134    public boolean setScanMode(int mode) {
1135        if (getState() != STATE_ON) return false;
1136        /* getDiscoverableTimeout() to use the latest from NV than use 0 */
1137        return setScanMode(mode, getDiscoverableTimeout());
1138    }

小結可檢測性這裡用到的類有:
BluetoothDiscoverableEnabler.java
BluetoothAdapter.java
LocalBluetoothManager

三、掃描藍芽
在/packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothSettings.java裡面呼叫方法startScanning() ,然後到/frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
裡面的函式

    public void startScanning(boolean force) {
151        // Only start if we're not already scanning
152        if (!mAdapter.isDiscovering()) {
153            if (!force) {
154                // Don't scan more than frequently than SCAN_EXPIRATION_MS,
155                // unless forced
156                if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
157                    return;
158                }
159
160                // If we are playing music, don't scan unless forced.
161                A2dpProfile a2dp = mProfileManager.getA2dpProfile();
162                if (a2dp != null && a2dp.isA2dpPlaying()) {
163                    return;
164                }
165            }
166
167            if (mAdapter.startDiscovery()) {//開始搜尋
168                mLastScan = System.currentTimeMillis();
169            }
170        }
171    }