Android平臺中,P2P操作特別簡單,用戶只需執行如下三個步驟。
1. 進入WifiP2pSettings界面。
2. 搜索周圍的P2P設備。搜索到的設備將顯示在WifiP2pSettings中。
3. 用戶選擇其中的某個設備以發起連接。
下面將根據上面的使用步驟來分析WifiP2pSettings。首先來看WifiP2pSettings的onActivityCreate函數。
**1、WifiP2pSettings創建**
WifiP2pSettings的onActivityCreated函數代碼如下所示。
**WifiP2pSettings.java::onActivityCreated**
~~~
public void onActivityCreated(Bundle savedInstanceState) {
addPreferencesFromResource(R.xml.wifi_p2p_settings);// 加載界面元素
/*
和第5章介紹的WifiSettings類似,WifiP2pSettings也是通過監聽廣播的方式來了解系統中
Wi-Fi P2P相關的信息及變化情況。下面這幾個廣播屬于P2P特有的,其作用如下。
WIFI_P2P_STATE_CHANGED_ACTION:用于通知系統中P2P功能的啟用情況,如該功能是enable還是disable。
WIFI_P2P_PEERS_CHANGED_ACTION:系統內部將保存搜索到的其他P2P設備信息,如果這些信息有變化,
則系統將發送該廣播。接收者需要通過WifiP2pManager的requestPeers函數重新獲取這些P2P設備的信息。
WIFI_P2P_CONNECTION_CHANGED_ACTION:用于通知P2P連接情況,該廣播可攜帶WifiP2pInfo
和NetworkInfo兩個對象。相關信息可從這兩個對象中獲取。
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION:用于通知本機P2P設備信息發生了變化。
WIFI_P2P_DISCOVERY_CHANGED_ACTION:用于通知P2P Device Discovery的工作狀態,如啟動或停止。
WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION:用于通知之persistent group信息發生了變化。
*/
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION);
final Activity activity = getActivity();
// 創建WifiP2pManager對象,它將和WifiP2pService交互
mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
if (mWifiP2pManager != null) {
// 初始化WifiManager并建立和WifiService的聯系
mChannel = mWifiP2pManager.initialize(activity, getActivity().getMainLooper(),null);
}
......
......// 創建UI中按鈕對應的onClickListener
mRenameListener = new OnClickListener() {......};
......
super.onActivityCreated(savedInstanceState);
}
~~~
WifiP2pSettings將在onResume中注冊一個廣播接收對象以監聽上面代碼中介紹的廣播事件。這部分代碼很簡單,請讀者自行閱讀。
**2、WifiP2pSettings工作流程**
**①、WIFI_P2P_STATE_CHANGED_ACTION處理流程**
打開WifiP2pSettings后,首先要等待WIFI_P2P_STATE_CHANGED_ACTION廣播以判斷P2P功能是否正常啟動。相應的處理函數如下所示。
**WifiP2pSettings.java::onReceive**
~~~
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
// 從WIFI_P2P_STATE_CHANGED_ACTION廣播中獲取相關狀態信息以判斷P2P功能是否打開
mWifiP2pEnabled = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE,
WifiP2pManager.WIFI_P2P_STATE_DISABLED) ==
WifiP2pManager.WIFI_P2P_STATE_ENABLED;
handleP2pStateChanged();
}
......
}
}
~~~
來看handleP2pStateChange函數,代碼如下所示。
**WifiP2pSettings.java::handleP2pStateChanged**
~~~
private void handleP2pStateChanged() {
updateSearchMenu(false);// 該函數將觸發WifiP2pSettings的onCreateOptionsMenu被調用
if (mWifiP2pEnabled) {
......
/*
獲取系統當前已經搜索到或者之前保存的P2P Device信息列表。Android為此定義了一個名為
WifiP2pDeviceList的數據類型用來存儲這些P2P Device信息。
請讀者注意requestPeers函數調用的第二個參數,該參數的類型為PeerListener,它是一個
接口類,而WifiP2pSettings實現了它。WifiP2pDeviceList信息將通過這個接口類的
onPeersAvailable函數返回給requestPeers的調用者。
后文將分析onPeersAvailable函數,此處先略過。
*/
mWifiP2pManager.requestPeers(mChannel, WifiP2pSettings.this);
}
}
~~~
根據上文的介紹,用戶下一步要做的事情就是主動搜索周圍的P2P設備。Android原生代碼中的WifiP2pSettings界面下方有兩個按鈕,分別是"SEARCH"和"RENAME"。
* "RENAME"用于更改本機的P2P設備名。
* "SEARCH"用于搜索周圍的P2P Device。
當P2P功能正常啟用后(即上述代碼中的mWifiP2pEnabled為true時),這兩個按鈕將被使能。此后,用戶就可單擊"SEARCH"按鈕以搜索周圍的P2P設備。該按鈕對應的函數是startSearch,馬上來看它。
>[info] 提示 一些手機廠商對WifiP2pSettings界面有所更改,但大體流程沒有變化。
**②、startSearch函數**
startSearch的代碼如下所示。
**WifiP2pSettings.java::startSearch**
~~~
private void startSearch() {
if (mWifiP2pManager != null && !mWifiP2pSearching) {
// discoverPeers將搜索周圍的P2P設備
mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
......});
}
}
~~~
上述代碼中,WifiP2pSettings通過調用WifiManager的discoverPeers來搜索周圍的設備。
當WPAS完成搜索后,WIFI_P2P_PEERS_CHANGED_ACTION廣播將被發送。來看WifiP2pSettings中對該廣播的處理。
**③、WIFI_P2P_PEERS_CHANGED_ACTION處理流程**
廣播事件在onReceive函數中被處理,此函數的代碼如下所示。
**WifiP2pSettings.java::onReceive**
~~~
public class WifiP2pSettings extends SettingsPreferenceFragment
implements PersistentGroupInfoListener, GroupInfoListener {
............
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
...............
// 如果搜索到新的P2P Device,則WIFI_P2P_PEERS_CHANGED_ACTION將被發送
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
mPeers = (WifiP2pDeviceList) intent.getParcelableExtra(
WifiP2pManager.EXTRA_P2P_DEVICE_LIST);
handlePeersChanged();
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
if (mWifiP2pManager == null) return;
NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(
WifiP2pManager.EXTRA_NETWORK_INFO);
WifiP2pInfo wifip2pinfo = (WifiP2pInfo) intent.getParcelableExtra(
WifiP2pManager.EXTRA_WIFI_P2P_INFO);
if (mWifiP2pManager != null) {
// requestGroupInfo第二個參數的類型是GroupInfoListener,用于返回Group信息
mWifiP2pManager.requestGroupInfo(mChannel, WifiP2pSettings.this);
}
if (networkInfo.isConnected()) {
if (DBG) Log.d(TAG, "Connected");
} else if (mLastGroupFormed != true) {
startSearch();// 如果沒有加入某個P2P Group,則重新發起設備掃描
}
mLastGroupFormed = wifip2pinfo.groupFormed;
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
mThisDevice = (WifiP2pDevice) intent.getParcelableExtra(
WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
if (DBG) Log.d(TAG, "Update device info: " + mThisDevice);
updateDevicePref();
} else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) {
int discoveryState = intent.getIntExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE,
WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED);
if (DBG) Log.d(TAG, "Discovery state changed: " + discoveryState);
if (discoveryState == WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED) {
updateSearchMenu(true);// 更新“SEARCH”按鈕顯示的名稱
} else {
updateSearchMenu(false);
}
} else if (WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION.equals(action)) {
if (mWifiP2pManager != null) {
mWifiP2pManager.requestPersistentGroupInfo(mChannel, WifiP2pSettings.this);
}
}
}
};
............
}
~~~
注意,startSearch還將觸發系統發送WIFI_P2P_DISCOVERY_CHANGED_ACTION廣播,WifiP2pSettings將根據該廣播攜帶的信息來更新"SEARCH"按鈕的界面,其規則是:如果P2PDiscovery啟動成功(即狀態變WIFI_P2P_DISCOVERY_STARTED),則"SEARCH"按鈕名顯示為"Searching...",否則該按鈕名顯示為"Search For Devices"。
當系統搜索到新的P2P Device后,WIFI_P2P_PEERS_CHANGED_ACTION廣播將被發送,而WifiP2pSettings對于該廣播的處理就是調用WifiP2pManager的requestPeers來獲取系統保存的P2P Device信息列表。
前文代碼中曾介紹過requestPeers,系統中所有的P2P設備信息將通過PeerListener接口類的onPeersAvailable函數返回給WifiP2pSettings。直接來看該函數,代碼如下所示。
**WifiP2pSettings.java::onPeersAvailable**
~~~
public void onPeersAvailable(WifiP2pDeviceList peers) {
// 系統中所有的P2P設備信息都保存在這個類型為WifiP2pDeviceList的peers對象中
mPeersGroup.removeAll();// mPeersGroup類型為PerferenceGroup,屬于UI相關的類
mPeers = peers;
mConnectedDevices = 0;
for (WifiP2pDevice peer: peers.getDeviceList()) {
// WifiP2pPeer是Perference的子類,它和UI相關
mPeersGroup.addPreference(new WifiP2pPeer(getActivity(), peer));
if (peer.status == WifiP2pDevice.CONNECTED)
mConnectedDevices++;
}
}
~~~
在onPeersAvailable函數中,WifiP2pDeviceList中保存的每一個WifiP2pDevice信息將作為一個Preference項添加到mPeersGroup中并顯示在UI界面上。
接下來,用戶就可在界面中選擇某個P2P Device并與之連接。這個步驟由onPreferenceTreeClick函數來完成。
提示 上述代碼中提到的WifiP2pDevice等數據結構將放到下文再介紹。
**④、onPreferenceTreeClick函數**
onPreferenceTreeClick的代碼如下所示。
**WifiP2pSettings.java::onPreferenceTreeClick**
~~~
public class WifiP2pSettings extends SettingsPreferenceFragment
implements PersistentGroupInfoListener, GroupInfoListener {
............
@Override
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
if (preference instanceof WifiP2pPeer) {
mSelectedWifiPeer = (WifiP2pPeer) preference;// 獲取用戶指定的那一個WifiP2pPeer項
if (mSelectedWifiPeer.device.status == WifiP2pDevice.CONNECTED) {
showDialog(DIALOG_DISCONNECT);// 如果已經和該Device連接,則判斷是否需要與之斷開連接
} else if (mSelectedWifiPeer.device.status == WifiP2pDevice.INVITED) {
showDialog(DIALOG_CANCEL_CONNECT);
} else {// 向對端P2P設備發起連接
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = mSelectedWifiPeer.device.deviceAddress;
// 判斷系統是否強制使用了某種WSC配置方法
int forceWps = SystemProperties.getInt("wifidirect.wps", -1);
if (forceWps != -1) {
config.wps.setup = forceWps;
} else {
// 獲取對端P2P Device支持的WSC配置方法,優先考慮PBC
if (mSelectedWifiPeer.device.wpsPbcSupported()) {
config.wps.setup = WpsInfo.PBC;
} else if (mSelectedWifiPeer.device.wpsKeypadSupported()) {
config.wps.setup = WpsInfo.KEYPAD;
} else {
config.wps.setup = WpsInfo.DISPLAY;
}
}
// 通過WifiP2pManager的connect函數向對端P2P Device發起連接。注意,目標設備
// 信息保存在config對象中
mWifiP2pManager.connect(mChannel, config,
new WifiP2pManager.ActionListener() {
public void onSuccess() {
if (DBG) Log.d(TAG, " connect success");
}
public void onFailure(int reason) {
Log.e(TAG, " connect fail " + reason);
Toast.makeText(getActivity(),
R.string.wifi_p2p_failed_connect_message,
Toast.LENGTH_SHORT).show();
}
});
}
} else if (preference instanceof WifiP2pPersistentGroup) {
mSelectedGroup = (WifiP2pPersistentGroup) preference;
showDialog(DIALOG_DELETE_GROUP);
}
return super.onPreferenceTreeClick(screen, preference);
}
..............
}
~~~
**⑤、WIFI_P2P_CONNECTION_CHANGED_ACTION處理流程**
當系統完成和指定P2P Device的連接后,WifiP2pSettings將收到
WIFI_P2P_CONNECTION_CHANGED_ACTION廣播,其對應的代碼邏輯如下所示。
**WifiP2pSettings.java::onReceive**
~~~
public class WifiP2pSettings extends SettingsPreferenceFragment
implements PersistentGroupInfoListener, GroupInfoListener {
............
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
...............
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
...............
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
if (mWifiP2pManager == null) return;
NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(
WifiP2pManager.EXTRA_NETWORK_INFO);
WifiP2pInfo wifip2pinfo = (WifiP2pInfo) intent.getParcelableExtra(
WifiP2pManager.EXTRA_WIFI_P2P_INFO);
if (mWifiP2pManager != null) {
// requestGroupInfo第二個參數的類型是GroupInfoListener,用于返回Group信息
mWifiP2pManager.requestGroupInfo(mChannel, WifiP2pSettings.this);
}
if (networkInfo.isConnected()) {
if (DBG) Log.d(TAG, "Connected");
} else if (mLastGroupFormed != true) {
startSearch();// 如果沒有加入某個P2P Group,則重新發起設備掃描
}
mLastGroupFormed = wifip2pinfo.groupFormed;
}
.................
}
};
............
}
~~~
當設備加入一個Group后,requestGroupInfo將通過其第二個參數設置的回調函數以返回此Group的信息,這個回調函數由GroupInfoListener接口類定義,WifiP2pSettings只需實現該接口類的onGroupInfoAvailable,相關代碼如下所示。
**WifiP2pSettings.java::onGroupInfoAvailable**
~~~
public void onGroupInfoAvailable(WifiP2pGroup group) {
mConnectedGroup = group; // 保存當前所加入的Group的信息
updateDevicePref(); // 更新WifiP2pPeer的界面
}
~~~
以上是WifiP2pSettings的大體工作流程,讀者只要把握幾個重要廣播的處理流程即可掌握Settings應用中和Wi-Fi P2P相關的知識。
**3、WifiP2pSettings總結**
上述代碼中有兩個比較重要的數據結構,WifiP2pDevice和WifiP2pGroup,成員比較簡單,此處不贅述。它們的類圖如圖7-23所示。
:-: 
圖7-23 WifiP2pDevice和WifiP2pGroup類圖
通過上面幾節的代碼可知,WifiP2pSettings將借助WifiP2pManager和系統中的WifiP2pService交互。WifiP2pSettings主要使用WifiP2pManager的幾個重要函數。
* **initialize**:初始化WifiP2pManager,其內部將和WifiP2pService通過AsyncChannel建立交互關系。
* **discoverPeers**:觸發WifiP2pService發起P2P Device掃描工作。
* **requestPeers**:獲取系統中保存的P2P Device信息。
* **connect**:和指定P2P Device發起連接,也就是相互協商以創建或加入一個P2P網絡,即一個Group。
* **requestGroupInfo**:獲取當前連接上的Group信息。
下面來看WifiP2pService,它是Android系統中P2P功能的Java層核心模塊。
- 前言
- 第1章 準備工作
- 1.1 Android系統架構
- 1.2 工具使用
- 1.2.1 Source Insight的使用
- 1.2.2 Eclipse的使用
- 1.2.3 BusyBox的使用
- 1.3 本書資源下載說明
- 第2章 深入理解Netd
- 2.1 概述
- 2.2 Netd工作流程
- 2.2.1 main函數分析
- 2.2.2 NetlinkManager分析
- 2.2.3 CommandListener分析
- 2.2.4 DnsProxyListener分析
- 2.2.5 MDnsSdListener分析
- 2.3 CommandListener中的命令
- 2.3.1 iptables、tc和ip命令
- 2.3.2 CommandListener構造函數和測試工具ndc
- 2.3.3 InterfaceCmd命令
- 2.3.4 IpFwd和FirewallCmd命令
- 2.3.5 ListTtysCmd和PppdCmd命令
- 2.3.6 BandwidthControlCmd和IdletimerControlCmd命令
- 2.3.7 NatCmd命令
- 2.3.8 TetherCmd和SoftapCmd命令
- 2.3.9 ResolverCmd命令
- 2.4 NetworkManagementService介紹
- 2.4.1 create函數詳解
- 2.4.2 systemReady函數詳解
- 2.5 本章總結和參考資料說明
- 2.5.1 本章總結
- 2.5.2 參考資料說明
- 第3章 Wi-Fi基礎知識
- 3.1 概述
- 3.2 無線電頻譜和802.11協議的發展歷程
- 3.2.1 無線電頻譜知識
- 3.2.2 IEEE 802.11發展歷程
- 3.3 802.11無線網絡技術
- 3.3.1 OSI基本參考模型及相關基本概念
- 3.3.2 802.11知識點導讀
- 3.3.3 802.11組件
- 3.3.4 802.11 Service介紹
- 3.3.5 802.11 MAC服務和幀
- 3.3.6 802.11 MAC管理實體
- 3.3.7 無線網絡安全技術知識點
- 3.4 Linux Wi-Fi編程API介紹
- 3.4.1 Linux Wireless Extensions介紹
- 3.4.2 nl80211介紹
- 3.5 本章總結和參考資料說明
- 3.5.1 本章總結
- 3.5.2 參考資料說明
- 第4章 深入理解wpa_supplicant
- 4.1 概述
- 4.2 初識wpa_supplicant
- 4.2.1 wpa_supplicant架構
- 4.2.2 wpa_supplicant編譯配置
- 4.2.3 wpa_supplicant命令和控制API
- 4.2.4 git的使用
- 4.3 wpa_supplicant初始化流程
- 4.3.1 main函數分析
- 4.3.2 wpa_supplicant_init函數分析
- 4.3.3 wpa_supplicant_add_iface函數分析
- 4.3.4 wpa_supplicant_init_iface函數分析
- 4.4 EAP和EAPOL模塊
- 4.4.1 EAP模塊分析
- 4.4.2 EAPOL模塊分析
- 4.5 wpa_supplicant連接無線網絡分析
- 4.5.1 ADD_NETWORK命令處理
- 4.5.2 SET_NETWORK命令處理
- 4.5.3 ENABLE_NETWORK命令處理
- 4.6 本章總結和參考資料說明
- 4.6.1 本章總結
- 4.6.2 參考資料說明
- 第5章 深入理解WifiService
- 5.1 概述
- 5.2 WifiService的創建及初始化
- 5.2.1 HSM和AsyncChannel介紹
- 5.2.2 WifiService構造函數分析
- 5.2.3 WifiStateMachine介紹
- 5.3 加入無線網絡分析
- 5.3.1 Settings操作Wi-Fi分析
- 5.3.2 WifiService操作Wi-Fi分析
- 5.4 WifiWatchdogStateMachine介紹
- 5.5 Captive Portal Check介紹
- 5.6 本章總結和參考資料說明
- 5.6.1 本章總結
- 5.6.2 參考資料說明
- 第6章 深入理解Wi-Fi Simple Configuration
- 6.1 概述
- 6.2 WSC基礎知識
- 6.2.1 WSC應用場景
- 6.2.2 WSC核心組件及接口
- 6.3 Registration Protocol詳解
- 6.3.1 WSC IE和Attribute介紹
- 6.3.2 802.11管理幀WSC IE設置
- 6.3.3 EAP-WSC介紹
- 6.4 WSC代碼分析
- 6.4.1 Settings中的WSC處理
- 6.4.2 WifiStateMachine的處理
- 6.4.3 wpa_supplicant中的WSC處理
- 6.4.4 EAP-WSC處理流程分析
- 6.5 本章總結和參考資料說明
- 6.5.1 本章總結
- 6.5.2 參考資料說明
- 第7章 深入理解Wi-Fi P2P
- 7.1 概述
- 7.2 P2P基礎知識
- 7.2.1 P2P架構
- 7.2.2 P2P Discovery技術
- 7.2.3 P2P工作流程
- 7.3 WifiP2pSettings和WifiP2pService介紹
- 7.3.1 WifiP2pSettings工作流程
- 7.3.2 WifiP2pService工作流程
- 7.4 wpa_supplicant中的P2P
- 7.4.1 P2P模塊初始化
- 7.4.2 P2P Device Discovery流程分析
- 7.4.3 Provision Discovery流程分析
- 7.4.4 GO Negotiation流程分析
- 7.5 本章總結和參考資料說明
- 7.5.1 本章總結
- 7.5.2 參考資料說明
- 第8章 深入理解NFC
- 8.1 概述
- 8.2 NFC基礎知識
- 8.2.1 NFC概述
- 8.2.2 NFC R/W運行模式
- 8.2.3 NFC P2P運行模式
- 8.2.4 NFC CE運行模式
- 8.2.5 NCI原理
- 8.2.6 NFC相關規范
- 8.3 Android中的NFC
- 8.3.1 NFC應用示例
- 8.3.2 NFC系統模塊
- 8.4 NFC HAL層討論
- 8.5 本章總結和參考資料說明
- 8.5.1 本章總結
- 8.5.2 參考資料說明
- 第9章 深入理解GPS
- 9.1 概述
- 9.2 GPS基礎知識
- 9.2.1 衛星導航基本原理
- 9.2.2 GPS系統組成及原理
- 9.2.3 OMA-SUPL協議
- 9.3 Android中的位置管理
- 9.3.1 LocationManager架構
- 9.3.2 LocationManager應用示例
- 9.3.3 LocationManager系統模塊
- 9.4 本章總結和參考資料說明
- 9.4.1 本章總結
- 9.4.2 參考資料說明
- 附錄