Android 藍牙開發(十一)Pan藍牙共享網絡分析

轉載請註明出處:http://blog.csdn.net/vnanyesheshou/article/details/71106622

本文已授權微信公衆號 fanfan程序媛 獨家發佈 掃一掃文章底部的二維碼或在微信搜索 fanfan程序媛 即可關注

本文主要分析Andorid藍牙共享網絡的使用、連接流程等。
基於Android4.3源碼


1 簡介

Bluetooth PAN全稱:Bluetooth Personal Area Networking,藍牙個人區域網,是Bluetooth技術的一種重要應用,其核心思想就是用Bluetooth無線技術取代傳統的有線電纜,組建個人化信息網絡,實現個人範圍的資源和信息共享(也就是網絡共享)。
主要應用場景:手機與手機、PC與PC、PC與手機之間的網絡共享。
三種角色:

NAP(Network Access Point): 如果你的藍牙設備支持NAP,那麼你可以通過共享網絡連接來給別的PAN Network內的PC提供上網功能。
GN(Group Ad-hoc Network): 使你可以在小局域網內給其它設備提供數據轉發的功能。
PANU(PAN User):與NAP,GN相對的角色,使用NAP,GN提供的功能的設備。

Android上支持作爲NAP和PANU角色。


2 NAP

NAP全稱NetworkAccessPoint(網絡接入點)。網絡接入點又稱爲網絡訪問點,是帶有一個或多個藍牙射頻的裝置,作爲LAN、GSM等網絡和藍牙網絡之間的網橋、代理或路由器的設備。網絡接入點爲每個相連的藍牙設備提供了網絡服務,如LAN上共享的資源。
要想藍牙共享網絡,首先設備需要連接wifi或者開啓流量。然後設置中開啓“藍牙共享網絡”。
這裏寫圖片描述
該界面對應着TetherSettings。
路徑:packages/apps/Settings/src/com/android/settings/TetherSettings.java
在其onCreate時,會獲取BluetoothPan代理對象。

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
    //獲取pan代理對象
    adapter.getProfileProxy(activity.getApplicationContext(), 
            mProfileServiceListener,
            BluetoothProfile.PAN);
}

getProfileProxy是異步的,獲取成功、失敗會回調mProfileServiceListener。代碼如下:

private BluetoothProfile.ServiceListener mProfileServiceListener =
    new BluetoothProfile.ServiceListener() {
    public void onServiceConnected(int profile, BluetoothProfile proxy) {
        //獲取成功
        mBluetoothPan.set((BluetoothPan) proxy);
    }
    public void onServiceDisconnected(int profile) {
        //獲取失敗
        mBluetoothPan.set(null);
    }
};

打開藍牙共享會調用到startTethering()。如果藍牙狀態爲關閉,則先開啓藍牙。保證藍牙爲開啓狀態,然後打開藍牙共享。

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
//判斷藍牙狀態
if (adapter.getState() == BluetoothAdapter.STATE_OFF) {
    mBluetoothEnableForTether = true;
    adapter.enable(); //打開藍牙
    mBluetoothTether.setSummary(R.string.bluetooth_turning_on);
    mBluetoothTether.setEnabled(false);
} else {
    BluetoothPan bluetoothPan = mBluetoothPan.get();
    //打開藍牙共享
    if (bluetoothPan != null) bluetoothPan.setBluetoothTethering(true);
    mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext);
}

bluetoothPan.setBluetoothTethering(true)跳到Bluetooth應用中,
代碼路徑:packages/apps/Bluetooth/src/com/android/bluetooth/pan/PanService.java
先調用到內部類BluetoothPanBinder的setBluetoothTethering方法。

public void setBluetoothTethering(boolean value) {
    PanService service = getService();
    if (service == null) return;
    service.setBluetoothTethering(value);
}

該方法中很明顯是去調用PanService的setBluetoothTethering方法。

void setBluetoothTethering(boolean value) {
    enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
    if(mTetherOn != value) {
        mTetherOn = value;  //保存狀態
        //在更改狀態時,刪除任何現有的panu、pan-nap連接
        List<BluetoothDevice> DevList = getConnectedDevices();
        for(BluetoothDevice dev : DevList)
            disconnect(dev);
    }
}

該函數主要是將狀態值保存喜愛,然後將之前的連接都斷開。
打開網絡共享後就可以進行連接互聯網共享了,當A設備打開網絡共享後,點擊互聯網訪問,連接B設備一直失敗,這樣是錯誤的,應該B設備主動連接該設備,而不是該設備連接其他設備。

當別的設備與NAP設備(該設備)連接成功,NAP會回調com_android_bluetooth_pan.cpp中的connection_state_callback(),然後回調PanService中的onConnectStateChanged(),然後跳到handlePanDeviceStateChange中,在該函數中由於遠端設備爲PANU,本地設備爲NAP,則會調用enableTethering,用來配置ip地址等相關信息(具體還不是很清楚)。handlePanDeviceStateChange會向爲發送廣播,攜帶藍牙共享的相關狀態。


3 PANU

PANU Personal Area Networking user,個人區域網用戶。
要想連接別的設備的藍牙共享網絡,首先需要配對,配對成功後,在已配對界面點擊“互聯網訪問”來連接遠端設備,
這裏寫圖片描述
該操作經過一系列調用,跳到PanProfile中的connect方法中。具體如何跳到PanProfile中的connect方法,可以參考如下文章。
http://blog.csdn.net/vnanyesheshou/article/details/71106622
http://blog.csdn.net/vnanyesheshou/article/details/71811288
PanProfile中的connect會跳到Bluetooth應用中的PanService中。
在PanService的connect函數中判斷與該設備的連接狀態是否斷開,沒有斷開則返回false。斷開着向handler發送消息,返回true。handler中處理該消息如下:

BluetoothDevice device = (BluetoothDevice) msg.obj;
//進行pan連接
if (!connectPanNative(Utils.getByteAddress(device),
        BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE)) {
    //連接失敗,發送狀態
    handlePanDeviceStateChange(device, null, BluetoothProfile.STATE_CONNECTING,
            BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE);
    handlePanDeviceStateChange(device, null,
            BluetoothProfile.STATE_DISCONNECTED, BluetoothPan.LOCAL_PANU_ROLE,
            BluetoothPan.REMOTE_NAP_ROLE);
    break;
}

調用connectPanNative進行pan的連接,返回false則表示失敗,向外發送廣播(CONNECTING、DISCONNECTED);返回true則表示該操作成功,等待連接狀態回調。
connectPanNative函數中的參數,看出本地設備作爲PANU角色,遠端作爲NAP角色,所以上面作爲NAP時主動連接其他設備失敗。
connectPanNative爲native方法,其會跳到com_android_bluetooth_pan,然後向hardware層調用。

連接狀態回調與上相同。都會回調到handlePanDeviceStateChange中。

//網絡相關,暫不清楚是怎麼回事。
LinkProperties lp = new LinkProperties();
lp.setInterfaceName(iface);             mTetherAc.sendMessage(NetworkStateTracker.EVENT_NETWORK_CONNECTED, lp);

然後向外發送連接狀態的廣播。該廣播只能判斷pan協議的連接狀態,並不能代表是否能正常共享網絡。因爲NAP端設備可能沒有連接網絡,或者分配ip地址等沒有成功。

public boolean isPanConnected(Context context){
    ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo btInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_BLUETOOTH);
    if(btInfo!=null){
        return btInfo.isConnected();
    }
    return false;
}

上述代碼可以判斷與NAP設備的網絡是否連接,但並不能保證可以上網,連接成功後,NAP設備不管可不可以上網,上述代碼都返回true。暫時還沒有找到其他方法。

歡迎掃一掃關注我的微信公衆號,定期推送優質技術文章:

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章