android 藍牙源碼分析

BluetoothService類中定義的Native方法都在android_server_BluetoothServer.cpp裏創建jni調用java

1、開啓(BT Turn on Turn off) (藍牙的打開關閉由類BluetoothEnabler控制。)

1.由BluetoothEnabler控制界面操做,在其構造函數裏會先調用 LocalBluetoothManager.getInstance(context)。
android

2.而後在LocalBluetoothManager類的getInstance函數裏會調用當前類下的init()函數,該init()函數中經過BluetoothAdapter.getDefaultAdapter()得到藍牙設備的句柄,若是當前沒有藍牙設備則返回null。 異步

3.初始化完畢會監聽checkbox的狀態,當觸發點擊checkbox會響應onPreferenceChange方法,其中將調用 LocalBluetoothManager.setBluetoothEnabled(enable)方法。函數

而LocalBluetoothManager.setBluetoothEnabled(enable)方法,會調用mAdapter.enable()方法,enable()方法又會調用 BluetoothService.enable()方法。其中,oop

(1)打開(關閉)操做成功後會有一個異步事件ACTION_STATE_CHANGED返回,異步事件由類BluetoothEventRedirector控制(接收廣播,進行處理)。在收到ACTION_STATE_CHANGED異步事件後,還須要作update本地設備profile的事情,讀取上次關閉前搜索到的藍牙設備。this

(1.1)update本地設備profile的事情:?spa

(1.2)讀取上次關閉前搜索到的藍牙設備:線程

經過LocalBluetoothManager.setBluetoothStateInt(int state)方法調到 CachedBluetoothDeviceManager.onBluetoothStateChanged方法來讀取上次關閉以前搜索到device. code

(2)來開啓EnableThread線程,進行打開操做,藍牙的打開關閉屬於異步操做。server

ps:在啓動藍牙的時候,要注意的地方是不能正常啓動藍牙的狀況,由於正常啓動的時候會返回BluetoothIntent.ENABLED_ACTION 這個Intent,當時當啓動出現異常的時候是沒有Intent返回的,android使用回調函數來解決這個問題。下面是在bluetoothdeviceservice.java 裏面enable(IBluetoothDeviceCallback callback 的過程:(如下代碼屬於較低版本的android源碼,與較高版本源碼中已有所不一樣,只做爲參考...)

 

View Code 
 public synchronized boolean enable(IBluetoothDeviceCallback callback) {
         checkPermissionBluetoothAdmin();
         Log.d(TAG,"start enable! ");
         // Airplane mode can prevent Bluetooth radio from being turned on.
         if (mIsAirplaneSensitive && isAirplaneModeOn()) {
             return false;
         }
         if (mIsEnabled) {
             return false;
         }
         if (mEnableThread != null && mEnableThread.isAlive()) {
             return false;
         }
    //   主要的啓動過程是放在一個新起的線程裏面,可是無論能不能啓動 
    //    仍然返回了true
         mEnableThread = new EnableThread(callback);
         mEnableThread.start();
       //   
         return true;
   
         }
    
     private EnableThread mEnableThread;
     private class EnableThread extends Thread {
         private final IBluetoothDeviceCallback mEnableCallback;
         public EnableThread(IBluetoothDeviceCallback callback) {
             mEnableCallback = callback;
         }
         public void run() {
             boolean res = enableNative();
             if (res) {
                 mEventLoop.start();
             }
 
             if (mEnableCallback != null) {
                 try {
                  
                     // 經過回調函數來代表是否正常啓動藍牙設備
                     mEnableCallback.onEnableResult(res ?
                                                    BluetoothDevice.RESULT_SUCCESS :
                                                    BluetoothDevice.RESULT_FAILURE);
                 } catch (RemoteException e) {}
             }
 
             if (res) {
                 mIsEnabled = true;
                 mIsDiscovering = false;
 
                 Intent intent = new Intent(BluetoothIntent.ENABLED_ACTION);
                 mContext.sendBroadcast(intent);
                 }
             }else{
                 mIsEnabled = false;
                 mIsDiscovering = false;
             }
             mEnableThread = null;
         }
 }
 
 
 
 
 
     
 
 //  這個回調函數將被做爲參數傳進bluetoothservice 裏面的enable(IBluetoothDeviceCallback callback)
 static class DeviceCallback extends IBluetoothDeviceCallback.Stub {
         Handler messageHandler;
 
         public void setHandler(Handler handler) {
             synchronized (this) {
                 messageHandler = handler;
             }
    
    
         public void onEnableResult(int result) {
             switch(result) {
 
   //  啓動不成功的時候執行
                 case BluetoothDevice.RESULT_FAILURE:
                      messageHandler.sendMessage(messageHandler.obtainMessage(EVENT_FAILED_BT_ENABLE,0));
                     break;
             }
         }
        
 
 //   配對完成時執行
 public void onCreateBondingResult(String address, int result) {
             synchronized (this) {
                 if (messageHandler != null) {
                     if (result == BluetoothDevice.RESULT_FAILURE) {
                         messageHandler.sendMessage(messageHandler.obtainMessage(
                                 HANDLE_PAIRING_FAILED, address));
                     } else {
                         messageHandler.sendMessage(messageHandler.obtainMessage(
                                 HANDLE_PAIRING_PASSED, address));
                     }
                 }
             }
         }
 
     }

涉及到的類: 

BluetoothService(最主要的類,開啓具體命令的線程進行enable,disable等操做) 
LocalBluetoothManager(本機藍牙設備管理,開啓關閉,搜索等等,初始化BluetoothAdapter) 
BluetoothEnabler(界面的點擊和狀態文字的顯示) 
BluetoothAdapter(framework封裝的類,提供本地藍牙設備的配置,包括開啓藍牙,搜索周圍藍牙設備,設置本地藍牙可見性;創建LocalBluetoothManager和BluetoothService的映射關係,主要是經過它調用BluetoothService的函數)

BluetoothEventRedirector(接收Bluetooth API 的廣播和回調,而且將Settings中的UI線程上的事件分派到正確的類)

 

2、可檢測性(Discoverable)

1.藍牙的discoverable mode由類BluetoothDiscoverableEnabler控制。點擊將觸發OnPreferenceChangeListener監聽事件,調用onPreferenceChange()方法,該方法中調用setEnabled(true),而setEnabled(true)方法將調用到BluetoothAdapter的setScanMode () 方法。

藍牙模式有兩種模式SCAN_MODE_CONNECTABLE_DISCOVERABLE(可鏈接可發現)和SCAN_MODE_CONNECTABLE(可鏈接但不可發現)

 
涉及到的類:
LocalBluetoothManager 
BluetoothDiscoverableEnabler 
BluetoothAdapter

 

3、掃描 

1.在BluetoothSetting裏觸發點擊,調用LocalBluetoothManager.startScanning(true)函數,經過BluetoothAdapter的startDiscovery調用到BluetoothService裏的startDiscovery來調用Native函數 startDiscoveryNative()。 

startDiscovery()是個異步函數,會當即返回,經過註冊 ACTION_DISCOVERY_STARTED、ACTION_DISCOVERY_FINISHED、ACTION_FOUND,來肯定當前的狀態。 

當藍牙由disable變成enable時會調用掃描,當距離上次掃描超過5分鐘的前提下,退出頁面,再進到頁面的時候也會啓動掃描。 

在啓動scan的時候,還會判斷當前是否在播放音樂,若是在播放音樂,則不啓動掃描。 

點擊查找設備後,會把設備列表裏沒有配對的設備清除掉,保留配對狀態的設備。

掃描的過程是一個很耗費資源的過程,在掃描過程,不會去嘗試進行新的鏈接,掃描時間默認是12秒,它是以一個系統服務的形式存在的,能夠調用cancelDiscovery()來取消掃描。 

 

4、鏈接 

1.1 在setting界面點擊鏈接,會調到CachedBluetoothDevice類的connect方法。

1.2 而connect方法會調用connectWithoutResettingTimer()方法。

1.3 而connectWithoutResettingTimer()方法會調用 connectInt方法。

在connectInt裏,根據不一樣的profile來得到profilemanger,而後調用 profilemanger.connect()函數 。此處的連接會涉及到的profile有A2DP AVRCP DUN HSP HFP 等。

同理若是配對或者解除配對,也會調到CachedBluetoothDevice類的pair()方法和unpair()。

 

以A2DP爲例,在connectInt裏,根據不一樣的profile來得到profilemanger,而後調用 profilemanger.connect()函數,在這個函數裏調用了BluetoothA2dpService的connectSink()函數,最後調到Native方法

connectSinkNative()去創建鏈接。 

涉及到的一些類: 

CachedBluetoothDevice(搜索到的設備) 
BluetoothDevice(設備類) 
LocalBluetoothProfileManager(是一個抽象類,各類ProfileManger,實例化各類Profile的service) 
SettingsBtStatus(藍牙的狀態類) 
BluetoothA2dp(爲LocalBluetoothProfileManager和BluetoothA2dpService創建映射關係) 
BluetoothA2dpService(最終的服務類,由它調用鏈接、斷開等Native函數,和底層通訊)

 

其餘文件做用(接收與發送相似)

1.BluetoothOppReceiver.java 這個類裏描述的是藍牙傳輸文件過程當中接收到的廣播事件。

2.BluetoothOppTransfer.java 管理文件傳輸的類

3. BluetoothOppService.java 藍牙傳輸文件後臺的類

4. BluetoothOppObexClientSession.java 具體實現文件傳輸的類

 

1 、開啓
  
步驟 1 :首先從BTSettings開始,執行onCreate方法。由於是初始化狀態,因此 if (action.equal(BTDevicePicker.ACTION_LAUNCH))不知足,故執行 else 語句。
  
步驟 2 :初始化mEnable對象,調用BTEnable構造函數。經過LocalBTManager.getInstance調用init方法,再經過init方法調用BTAdapter.getDefaultAdapter()得到適配器句柄。
  
步驟 3 :各類初始化完畢後,執行BTSettings中的onResume方法,調用BTEnabler.resume方法,該resume方法爲組合框設置監聽事件。
  
步驟 4 :當藍牙開啓時,該組合框被選中,將響應監聽事件,執行BTEnabler.onPreferenceChange方法。該方法中會調用LocalBTManager.setBTEnabled方法。而setBTEnabled方法會調用BTAdapter.enable()方法,繼而調用BTService.enable()方法,繼而調用BTService.enable( true )方法。在該方法中,
  
1 )當enable( true )方法返回 true 時,在setBTEnabled方法中會調用BTService中的setBTStateInt方法,繼而廣播出去,由BTEventRedirector類接收。
  
2 )開啓新的線程,主要的啓動過程是放在這個新啓動的線程裏面。
  
3 )開啓藍牙後,會調用CachedBTDeviceManager.onBTStateChanged方法來讀取上次關閉前搜索到的藍牙設備。
  
2 .可檢測的
  
點擊「可檢測性」組合框,將觸發BTDiscoverableEnabler.onPreferenceChange方法,而後調用同個類中的setEnabled方法,來調用BTAdapter.setScanMode方法(其中傳遞SCAN_MODE_CONNECTABLE_DISCOVERABLE參數),繼而會調用BTService.setScanMode方法,在該方法中,會經過setDiscoverableTimeout方法設置檢測時間。
  
3 .掃描
  
BTSettings的onResume方法繼續往下運行,將調用LocalBTManager.startScanning方法,該方法會調用BTAdapter.startDiscovery方法,繼而調用BTService.startDiscovery方法,再調用startDIscoveryNative方法。
  
4 .鏈接
  
步驟 1 :在setting界面點擊鏈接,會調到CachedBluetoothDevice類的connect方法。
  
步驟 2 :而connect方法會調用connectWithoutResettingTimer()方法。
  
步驟 3 :而connectWithoutResettingTimer()方法會調用 connectInt方法。
  
步驟 4 :在connectInt裏,根據不一樣的profile來得到profilemanger,而後調用 profilemanger.connect()函數 。此處的連接會涉及到的profile有A2DP AVRCP DUN HSP HFP 等。
  
同理若是配對或者解除配對,也會調到CachedBluetoothDevice類的pair()方法和unpair()。
相關文章
相關標籤/搜索