轉載請註明出處: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。暫時還沒有找到其他方法。
歡迎掃一掃關注我的微信公衆號,定期推送優質技術文章: