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所示。
:-: ![](https://box.kancloud.cn/2906cd519086eb9b4402fbcc359c7a12_1101x345.jpg)
图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 参考资料说明
- 附录