Android藍牙總結

最近在作Android藍牙這部份內容,因此查閱了不少相關資料,在此總結一下。java


基本概念

  • Bluetooth是一種短距離(10米)的無線通訊技術標準,藍牙協議分爲4層,即核心協議層、電纜替代協議層、電話控制協議層和採納的其它協議層。這4種協議中最重要的是核心協議。藍牙的核心協議包括基帶、鏈路管理、邏輯鏈路控制和適應協議四部分。其中鏈路管理(LMP)負責藍牙組件間鏈接的創建。邏輯鏈路控制與適應協議(L2CAP)位於基帶協議層上,屬於數據鏈路層,是一個爲高層傳輸和應用層協議屏蔽基帶協議的適配協議。android

  • 安卓平臺提供對藍牙的通信棧的支持,容許設別和其餘的設備進行無線傳輸數據。應用程序層經過安卓API來調用藍牙的相關功能,這些API使程序無線鏈接到藍牙設備,並擁有P2P或者多端無線鏈接的特性。api


  • 藍牙的功能:
  1. 掃描其餘藍牙設備
  2. 爲可配對的藍牙設備查詢藍牙適配器
  3. 創建RFCOMM通道(其實就是尼瑪的認證)
  4. 經過服務搜索來連接其餘的設備
  5. 與其餘的設備進行數據傳輸
  6. 管理多個鏈接
  • 藍牙創建鏈接必需要求:
  1. 打開藍牙
  2. 查找附近已配對或可用設備
  3. 鏈接設備
  4. 設備間數據交互

藍牙API


代碼分佈

packages/apps/Bluetooth/服務器

  • 藍牙應用,主要是關於藍牙應用協議的表現代碼,包括opp、hfp、hdp、a2dp、pan等等

frameworks/base/core/Java/android/server/網絡

  • 4.2之後這個目錄雖然還有,但裏面代碼已經轉移到應用層了,就是前面那個目錄,因此4.2.2上的藍牙這裏能夠忽略。

framework/base/core/java/android/bluetoothapp

  • 這個目錄裏的代碼更像一個橋樑,裏面有供java層使用一些類,也有對應的aidl文件聯繫C、C++部分的代碼,仍是挺重要的。

kernel\drivers\bluetoothBluetoothsocket

  • 具體協議實現。包括hci,hid,rfcomm,sco,SDP等協議

kernel\net\bluetooth Linux kerneltcp

  • 對各類接口的Bluetoothdevice的驅動。例如:USB接口,串口等,上面kernel這兩個目錄有可能看不到的,但必定會有的。

external\bluetooth\bluedroidide

  • 官方藍牙協議棧

system\bluetoothBluetooth函數

  • 適配層代碼,和framework那個做用相似,是串聯framework與協議棧的工具。

關鍵類

/frameworks/base/core/java/android/bluetooth/

  • BluetoothAdapter 表明本地藍牙適配器(藍牙發射的裝置),是全部藍牙交互的入口。經過它能夠搜索其它藍牙設備,查詢已經配對的設備列表,經過已知的MAC地址建立BluetoothDevice,建立BluetoothServerSocket監聽來自其它設備的通訊。
  • BluetoothDevice 表明了一個遠端的藍牙設備, 使用它請求遠端藍牙設備鏈接或者獲取 遠端藍牙設備的名稱、地址、種類和綁定狀態。 (其信息是封裝在 bluetoothsocket 中) 。
  • BluetoothSocket 表明了一個藍牙套接字的接口(相似於 tcp 中的套接字) ,他是應用程 序經過輸入、輸出流與其餘藍牙設備通訊的鏈接點。
  • BluetoothServerSocket 表明打開服務鏈接來監聽可能到來的鏈接請求 (屬於 server 端) , 爲了鏈接兩個藍牙設備必須有一個設備做爲服務器打開一個服務套接字。 當遠端設備發起連 接鏈接請求的時候,而且已經鏈接到了的時候,Blueboothserversocket 類將會返回一個 bluetoothsocket。
  • BluetoothClass 描述了一個設備的特性(profile)或該設備上的藍牙大體能夠提供哪些服務(service),但不可信。好比,設備是一個電話、計算機或手持設備;Blueboothserversocket 設備能夠提供audio/telephony服務等。能夠用它來進行一些UI上的提示。
  • BluetoothProfile 藍牙協議
  • BluetoothHeadset 提供手機使用藍牙耳機的支持。這既包括藍牙耳機和免提(V1.5)模式。
  • BluetoothA2dp 定義高品質的音頻,能夠從一個設備傳輸到另外一個藍牙鏈接。 「A2DP的」表明高級音頻分配模式。
  • BluetoothHealth 表明了醫療設備配置代理控制的藍牙服務
  • BluetoothHealthCallback 一個抽象類,使用實現BluetoothHealth回調。你必須擴展這個類並實現回調方法接收更新應用程序的註冊狀態和藍牙通道狀態的變化。
  • BluetoothHealthAppConfiguration 表明一個應用程序的配置,藍牙醫療第三方應用註冊與遠程藍牙醫療設備交流。
  • BluetoothProfile.ServiceListener 當他們已經鏈接到或從服務斷開時通知BluetoothProfile IPX的客戶時一個接口(即運行一個特定的配置文件,內部服務)。

\packages\apps\Settings\src\com\android\settings\bluetooth

  • BluetoothEnabler 界面上藍牙開啓、關閉的開關就是它了,
  • BluetoothSettings 主界面,用於管理配對和鏈接設備
  • LocalBluetoothManager 提供了藍牙API上的簡單調用接口,這裏只是開始。
  • CachedBluetoothDevice 描述藍牙設備的類,對BluetoothDevice的再封裝
  • BluetoothPairingDialog 那個配對提示的對話框

/packages/apps/Phone/src/com/android/phone/

  • BluetoothPhoneService 在phone的目錄確定和電話相關了,藍牙接聽掛斷電話會用到這個

/packages/apps/Bluetooth/src/com/android/bluetooth/

說到這裏不能不說4.2藍牙的目錄變了,在4.1及之前的代碼中packages層的代碼只有opp協議相關應用的代碼,也就是文件傳輸那部分,而4.2的代碼應用層的代碼則豐富了許多,按具體的藍牙應用協議來區別,分爲如下文件夾(這裏一併對藍牙一些名詞做個簡單解釋)

  • btservice 這個前面AdapterService.java的描述你們應該能猜到一些,關於藍牙基本操做的目錄,一切由此開始。

    • AdapterService (4.2後纔有的代碼)藍牙打開、關閉、掃描、配對都會走到這裏,其實更準確的說它替代了4.1以前的BluetoothService.java,原來的工做就由這個類來完成了。
  • a2dp (Advanced Audio Distribution Profile)高級音頻傳輸模式,藍牙立體聲,和藍牙耳機聽歌有關那些。

  • avrcp 音頻/視頻遠程控制配置文件,是用來聽歌時暫停,上下歌曲選擇的。

  • hdp (Health Device Profile)藍牙醫療設備模式,能夠建立支持藍牙的醫療設備,使用藍牙通訊的應用,例如心率監視器,血液,溫度計和秤。

  • hfp (Hands-free Profile)讓藍牙設備能夠控制電話,如接聽、掛斷、拒接、語音撥號等,拒接、語音撥號要視藍牙耳機及電話是否支持。

  • pbap (Phonebook Access Profile)電話號碼簿訪問協議

  • hid (The Human Interface Device)人機交互接口,藍牙鼠標鍵盤什麼的就是這個了。該協議改編自USB HID Protocol。

  • opp (Object Push Profile)對象存儲規範,最爲常見的,文件的傳輸都是使用此協議。

  • pan (Personal Area Network)描述了兩個或更多個藍牙設備如何構成一個即時網絡,和網絡有關還有串行端口功能(SPP),撥號網絡功能(DUN)

android 4.2的藍牙應用層部分代碼更豐富了,雖然有些目錄還沒具體代碼,不過說不許哪一個版本更新就有了,就像4.0添加了hdp醫療那部分同樣。另外本來在framework的JNI代碼也被移到packages/apps/bluetooth當中。


主要方法

  • BluetoothAdapter (藍牙本地適配器)

    • getDefaultAdapter() 獲得本地藍牙適配器
    • setName(String name) 設置藍牙名稱
    • disable() 關閉藍牙
    • enable() 打開藍牙
    • isEnabled() 判斷藍牙是否打開
    • getName() 獲得本地藍牙的名稱
    • getAddress() 獲得本地藍牙適配器的地址
    • getBondedDevices() 獲得已經綁定的藍牙的設備
    • getRemoteDevice(byte[] address) 獲得遠程藍牙設備
    • getRemoteDevice(String address) 獲得遠程藍牙設備
    • startDiscovery() 開始搜多附近藍牙
    • cancelDiscovery() 中止當前搜索藍牙的 Task
    • listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid) 建立 BluetoothServerSocket
  • BluetoothDevice (藍牙設備)

    • createBond() 藍牙配對 (低版本不支持,>=api19)
    • createRfcommSocketToServiceRecord(UUID uuid) 建立 BluetoothSocket
    • getBondState() 獲得配對的狀態
    • getAddress() 獲得遠程藍牙適配器的地址
    • getName() 獲得遠程藍牙的名稱
  • BluetoothServerSocket (數據傳輸服務端)
    這個類一共只有三個方法兩個重載的。兩個重載的區別在於後面的方法指定了過期時間,須要注意的是,執行這兩個方法的時候,直到接收到了客戶端的請求(或是過時以後),都會阻塞線程,應該放在新線程裏運行!

    • close() 關閉
    • connect() 鏈接
    • isConnected() 判斷當前的鏈接狀態
    • accept() 接收請求
    • accept(int timeout) 接收請求
  • BluetoothSocket (數據傳輸客戶端)

    • close() 關閉
    • connect() 鏈接
    • getInptuStream() 獲取輸入流
    • getOutputStream() 獲取輸出流
    • getRemoteDevice() 獲取遠程設備,這裏指的是獲取bluetoothSocket指定鏈接的那個遠程藍牙設備

藍牙操做


打開和關閉藍牙

開啓藍牙有兩種方法:

1、直接調用系統對話框啓動藍牙:

AndroidManifest.xml文件中添加須要的權限,高版本也不須要動態受權:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

而後,在代碼中執行:

startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 1);

若是不想讓用戶看到對話框,那麼咱們還能夠選擇第二種方法,進行靜默開啓藍牙。

2、靜默開啓,不會有方法一的對話框:

照樣在AndroidManifest.xml文件中添加須要的權限:

<!-- 已適配Android6.0 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />  
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />  
<uses-feature
    android:name="android.hardware.bluetooth_le"
    android:required="true" />

因爲藍牙所須要的權限包含Dangerous Permissions,因此咱們須要在Java代碼中進行動態受權處理:

private static final int REQUEST_BLUETOOTH_PERMISSION=10;

private void requestBluetoothPermission(){
    //判斷系統版本
    if (Build.VERSION.SDK_INT >= 23) {
        //檢測當前app是否擁有某個權限
        int checkCallPhonePermission = ContextCompat.checkSelfPermission(this, 
                Manifest.permission.ACCESS_COARSE_LOCATION);
        //判斷這個權限是否已經受權過
        if(checkCallPhonePermission != PackageManager.PERMISSION_GRANTED){
            //判斷是否須要 向用戶解釋,爲何要申請該權限
            if(ActivityCompat.shouldShowRequestPermissionRationale(this, 
                    Manifest.permission.ACCESS_COARSE_LOCATION))
                Toast.makeText(this,"Need bluetooth permission.", 
                        Toast.LENGTH_SHORT).show();
            ActivityCompat.requestPermissions(this ,new String[]
                    {Manifest.permission.ACCESS_COARSE_LOCATION},REQUEST_BLUETOOTH_PERMISSION);
            return;
        }else{
        }
    } else {
    }
}

接下來咱們就能夠靜默開啓藍牙了:

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.enable(); //開啓

關閉藍牙

if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
    mBluetoothAdapter.disable();
}

搜索藍牙設備

搜索分爲主動搜索和被動搜索:

1、被動搜索

if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) 
{
    Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
    // 設置被發現時間,最大值是3600秒,0表示設備老是能夠被發現的(小於0或者大於3600則會被自動設置爲120秒)
    discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);
    activity.startActivity(discoverableIntent);
}

2、主動搜索

建立BluetoothAdapter對象

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

咱們先獲取並顯示一下已經配對的藍牙設備列表

/*
 * 已配對設備列表
 */
private ListView mBoundDevicesLv;
/**
 * 顯示已配對的設備列表
 */
private void showBoundDevices() {
    List<Map<String, String>> mBoundDevicesList = new ArrayList<>();
    Set<BluetoothDevice> boundDeviceSet = mBluetoothAdapter.getBondedDevices();
    for (BluetoothDevice boundDevices : boundDeviceSet) {
        Map<String, String> mBoundDevicesMap = new HashMap<>();
        mBoundDevicesMap.put("name", boundDevices.getName());
        mBoundDevicesMap.put("address", boundDevices.getAddress());
        mBoundDevicesList.add(mBoundDevicesMap);
    }
    SimpleAdapter mSimpleAdapter = new SimpleAdapter(MainActivity.this, mBoundDevicesList,
            android.R.layout.simple_list_item_2,
            new String[]{"name", "address"},
            new int[]{android.R.id.text1, android.R.id.text2});
    mBoundDevicesLv.setAdapter(mSimpleAdapter);
}

開始搜索

if (mBluetoothAdapter == null) {
    LogUtil.e(TAG, "設備不支持藍牙");
}
// 打開藍牙       
if (!mBluetoothAdapter.isEnabled()) {
    BluetoothAdapter.enable();
    mBluetoothAdapter.cancelDiscovery();
}
// 尋找藍牙設備,android會將查找到的設備以廣播形式發出去       
while (!mBluetoothAdapter.startDiscovery()) {
    LogUtil.e(TAG, "嘗試失敗");
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }   
}

定義搜索結果的廣播接收器

// 設置廣播信息過濾
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);//每搜索到一個設備就會發送一個該廣播
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//當所有搜索完後發送該廣播
filter.setPriority(Integer.MAX_VALUE);//設置優先級
registerReceiver(receiver, filter);// 註冊藍牙搜索廣播接收者,接收並處理搜索結果

搜索藍牙設備的廣播接收器以下:

/**
 * 搜索出的設備集合
 */
private List<Map<String, String>> devices = new ArrayList<>();
/**
 * 發現的設備列表
 */
private ListView mDevicesLv;
/**
 * 定義廣播接收器
 */
private final BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            ToastUtil.showToast(MainActivity.this, "Showing Devices");
                // 從Intent中獲取設備對象
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // 定義一個裝載藍牙設備名字和地址的Map
                Map<String, String> deviceMap = new HashMap<>();
                // 過濾已配對的和重複的藍牙設備
                if ((device.getBondState() != BluetoothDevice.BOND_BONDED) && isSingleDevice(device)) {
                    deviceMap.put("name", device.getName() == null ? "null" : device.getName());
                    deviceMap.put("address", device.getAddress());
                    devices.add(deviceMap);
                }
                // 顯示發現的藍牙設備列表
                mDevicesLv.setVisibility(View.VISIBLE);
                // 加載設備
                showDevices();
        } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
            //已搜素完成
        }
    }
};定義服務端線程類:

/**
 * 判斷此設備是否存在
 */
private boolean isSingleDevice(BluetoothDevice device) {
    if (devices == null) {
        return true;
    }
    for (Map<String, String> mDeviceMap : devices) {
        if ((device.getAddress()).equals(mDeviceMap.get("address"))) {
            return false;
        }
    }
    return true;
}

/**
 * 顯示搜索到的設備列表
 */
private void showDevices() {
    SimpleAdapter mSimpleAdapter = new SimpleAdapter(MainActivity.this, devices,
            android.R.layout.simple_list_item_2,
            new String[]{"name", "address"},
            new int[]{android.R.id.text1, android.R.id.text2});
    mDevicesLv.setAdapter(mSimpleAdapter);
}

藍牙配對

當咱們搜索到了藍牙的以後,就須要配對,由於只有在配對以後才能鏈接。

在上面的搜索到的設備列表的點擊事件中,進行配對。

BluetoothDevice device = (BluetoothDevice) adapter.getItem(i);
if (device.getBondState() == BluetoothDevice.BOND_BONDED) {//是否已配對
    connect(device);
} else {
    try {
        Method boned=device.getClass().getMethod("createBond");
        boolean isok= (boolean) boned.invoke(device);
        if(isOk) {
            connect(device);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }         
}

這裏須要說明的是,這個配對Android在API19以後對外提供了createBond()這個方法。可是在API19之前並無這個方法,因此用反射兼容性比較好。


藍牙的UUID

在進行藍牙鏈接以前,先介紹一下一個關鍵的東西:兩個藍牙設備進行鏈接時須要使用同一個UUID。但不少讀者可能發現,有不少型號的手機(多是非Android系統的手機)之間使用了不一樣的程序也可使用藍牙進行通信。從表面上看,它們之間幾乎不可能使用同一個UUID。

UUID的格式以下:

xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

UUID的格式被分紅5段,其中中間3段的字符數相同,都是4,第1段是8個字符,最後一段是12個字符。因此UUID其實是一個8-4-4-4-12的字符串。

實際上,UUID和TCP的端口同樣,也有一些默認的值。例如,將藍牙模擬成串口的服務就使用了一個標準的UUID:

00001101-0000-1000-8000-00805F9B34FB

除此以外,還有不少標準的UUID,以下面就是兩個標準的UUID:

信息同步服務:00001104-0000-1000-8000-00805F9B34FB
文件傳輸服務:00001106-0000-1000-8000-00805F9B34FB


藍牙設備間的數據傳輸

藍牙傳輸數據與Socket相似。在網絡中使用Socket和ServerSocket控制客戶端和服務端的數據讀寫。而藍牙通信也由客戶端和服務端Socket來完成。藍牙客戶端Socket是BluetoothSocket,藍牙服務端Socket是BluetoothServerSocket。這兩個類都在android.bluetooth包中。

不管是BluetoothSocket,仍是BluetoothServerSocket,都須要一個UUID(全局惟一標識符,Universally Unique Identifier),UUID至關於Socket的端口,而藍牙地址至關於Socket的IP。

下面,咱們開始進行模擬一個藍牙數據的傳輸:

1、首先來看客戶端:

定義全局常量變量:

private ListView mDevicesLv;
private BluetoothAdapter mBluetoothAdapter;
private List<Map<String, String>> devices = new ArrayList<>();
//隨便定義一個UUID
private final UUID MY_UUID = UUID.fromString("abcd1234-ab12-ab12-ab12-abcdef123456");
private BluetoothSocket clientSocket;
private BluetoothDevice device;  
private OutputStream os;//輸出流

接下來咱們設置設備列表的點擊事件

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    Map<String, String> s = devices.get(i);
    String address = s.get("address");//把地址解析出來
    //主動鏈接藍牙服務端
    try {
        // 若是當前正在搜索,則取消搜索。
        if (mBluetoothAdapter.isDiscovering()) {
            mBluetoothAdapter.cancelDiscovery();
        }
        try {
            if (device == null) {
                //得到遠程設備
                device = mBluetoothAdapter.getRemoteDevice(address);
            }
            if (clientSocket == null) {
                //建立客戶端藍牙Socket
                clientSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
                //開始鏈接藍牙,若是沒有配對則彈出對話框提示咱們進行配對
                clientSocket.connect();
                //得到輸出流(客戶端指向服務端輸出文本)
                os = clientSocket.getOutputStream();
            }
        } catch (Exception e) {
        }
        if (os != null) {
            //往服務端寫信息
            os.write("藍牙信息來了".getBytes("utf-8"));
        }
    } catch (Exception e) {
    }
}

2、接下來看服務端:

服務端使用的是另外一部手機,接受上面手機經過藍牙發送過來的信息並顯示。

定義全局常量變量:

private BluetoothAdapter mBluetoothAdapter;
private AcceptThread acceptThread;
// 和客戶端相同的UUID
private final UUID MY_UUID = UUID.fromString("abcd1234-ab12-ab12-ab12-abcdef123456");
private final String NAME = "Bluetooth_Socket";
private BluetoothServerSocket serverSocket;
private BluetoothSocket socket;
private InputStream is;//輸入流

定義服務端線程類:

private Handler handler = new Handler() {
    public void handleMessage(Message msg) {
        Toast.makeText(getApplicationContext(), String.valueOf(msg.obj),
                Toast.LENGTH_LONG).show();
        super.handleMessage(msg);
    }
};

// 服務端監聽客戶端的線程類
private class AcceptThread extends Thread {
    public AcceptThread() {
        try {
            serverSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
        } catch (Exception e) {
        }
    }
    public void run() {
        try {
            socket = serverSocket.accept();
            is = socket.getInputStream();
            while(true) {
                byte[] buffer =new byte[1024];
                int count = is.read(buffer);
                Message msg = new Message();
                msg.obj = new String(buffer, 0, count, "utf-8");
                handler.sendMessage(msg);
            }
        }
        catch (Exception e) {
        }
    }
}

在onCreate方法中初始化線程類並開啓:

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
acceptThread = new AcceptThread();
acceptThread.start();

注意,使用socket.getInputStream接收到的數據是字節流,這樣的數據是無法分析的,因此不少狀況須要一個byte轉十六進制String的函數:

public static String bytesToHex(byte[] bytes) { 
    char[] hexChars = new char[bytes.length * 2]; 
    for ( int j = 0; j < bytes.length; j++ ) {     
        int v = bytes[j] & 0xFF;     
        hexChars[j * 2] = hexArray[v >>> 4];     
        hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 
    } 
    return new String(hexChars);
}

藍牙協議


藍牙協議簡介

從Android 3.0開始,Bluetooth API就包含了對Bluetooth profiles的支持。

Bluetooth profile是基於藍牙的設備之間通訊的無線接口規範。

你在你的類裏能夠完成BluetoothProfile接口來支持某一Bluetooth profile。

Android Bluetooth API完成了下面的Bluetooth profile:

  1. Headset profile提供了移動電話上的Bluetooth耳機支持。Android提供了BluetoothHeadset類,它是一個協議,用來經過IPC(interprocess communication)控制Bluetooth Headset Service。BluetoothHeadset既包含Bluetooth Headset profile也包含Hands-Free profile,還包括對AT命令的支持。
  2. HFP (Hands-free Profile),免提模式,讓藍牙設備能夠控制電話,如接聽、掛斷、拒接、語音撥號等,拒接、語音撥號要視藍牙耳機及電話是否支持。
  3. HDP(Health Device Profile.),藍牙醫療設備模式,能夠建立支持藍牙的醫療設備,使用藍牙通訊的應用,例如心率監視器,血液,溫度計和秤。
  4. AVRCP,音頻/視頻遠程控制配置文件,是用來聽歌時暫停,上下歌曲選擇的。
  5. A2DP(Advanced Audio Distribution Profile),高級音頻傳輸模式。Android提供了BluetoothA2dp類,這是一個經過IPC來控制Bluetooth A2DP的協議。
  6. HID (The Human Interface Device),人機交互接口,藍牙鼠標鍵盤什麼的就是這個了。該協議改編自USB HID Protocol。
  7. OPP (Object Push Profile),對象存儲規範,最爲常見的,文件的傳輸都是使用此協議。
  8. PAN (Personal Area Network),描述了兩個或更多個藍牙設備如何構成一個即時網絡,和網絡有關還有串行端口功能(SPP),撥號網絡功能(DUN)。
  9. PBAP (Phonebook Access Profile),電話號碼簿訪問協議。

藍牙協議的使用

下面是使用profile的基本步驟:

  1. 獲取默認的Bluetooth適配器。
  2. 使用getProfileProxy()來創建一個與profile相關的profile協議對象的鏈接。在下面的例子中,profile協議對象是BluetoothHeadset的一個實例。
  3. 設置BluetoothProfile.ServiceListener。該listener通知BluetoothProfile IPC客戶端,當客戶端鏈接或斷連服務器的時候
  4. 在BluetoothProfile.ServiceListener的onServiceConnected()內,獲得一個profile協議對象的句柄。
  5. 一旦擁有了profile協議對象,就能夠用它來監控鏈接的狀態,完成於該profile相關的其餘操做。

例如,下面的代碼片斷顯示如何鏈接到一個BluetoothHeadset協議對象,用來控制Headset profile:

BluetoothHeadset mBluetoothHeadset;
// 獲取默認的Bluetooth適配器
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 鏈接Headset profile
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);
private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener(){
    public void onServiceConnected(int profile, BluetoothProfile proxy) {
        if (profile == BluetoothProfile.HEADSET) {
            mBluetoothHeadset = (BluetoothHeadset) proxy;
        }
    }
    public void onServiceDisconnected(int profile) {
        if (profile == BluetoothProfile.HEADSET) {
            mBluetoothHeadset = null;
        }
    }
};

// ... 使用 mBluetoothHeadset

// 使用以後,關閉Proxy
mBluetoothAdapter.closeProfileProxy(mBluetoothHeadset)

以上,就先分析到這兒吧

相關文章
相關標籤/搜索