本文为《深入理解Android Wi-Fi、NFC和GPS卷》读书笔记,Android源码为Android 5.1

Android平台中,P2P操作用户只需执行如下三个步骤:
1)进入WifiP2pSettings界面;
2)搜索周围的P2P设备。搜索到的设备将显示在WifiP2pSettings中。
3)用户选择其中的某个设备以发起连接。
首先来看WifiP2pSettings的onActivityCreate函数。
1.WifiP2pSettings创建

android-5.1/packages/apps/Settings/src/com/android/settings/wifi/p2p/WifiP2pSettings.java

    public void onActivityCreated(Bundle savedInstanceState) {addPreferencesFromResource(R.xml.wifi_p2p_settings);//加载界面元素/*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);if (mChannel == null) {//Failure to set up connectionLog.e(TAG, "Failed to set up connection with wifi p2p service");mWifiP2pManager = null;}} else {Log.e(TAG, "mWifiP2pManager is null !");}if (savedInstanceState != null && savedInstanceState.containsKey(SAVE_DIALOG_PEER)) {WifiP2pDevice device = savedInstanceState.getParcelable(SAVE_DIALOG_PEER);mSelectedWifiPeer = new WifiP2pPeer(getActivity(), device);}if (savedInstanceState != null && savedInstanceState.containsKey(SAVE_DEVICE_NAME)) {mSavedDeviceName = savedInstanceState.getString(SAVE_DEVICE_NAME);}if (savedInstanceState != null && savedInstanceState.containsKey(SAVE_SELECTED_GROUP)) {mSelectedGroupName = savedInstanceState.getString(SAVE_SELECTED_GROUP);}//创建UI中按钮对应的onClickListenermRenameListener = new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {if (which == DialogInterface.BUTTON_POSITIVE) {if (mWifiP2pManager != null) {mWifiP2pManager.setDeviceName(mChannel,mDeviceNameText.getText().toString(),new WifiP2pManager.ActionListener() {public void onSuccess() {if (DBG) Log.d(TAG, " device rename success");}public void onFailure(int reason) {Toast.makeText(getActivity(),R.string.wifi_p2p_failed_rename_message,Toast.LENGTH_LONG).show();}});}}}};//disconnect dialog listenermDisconnectListener = new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {if (which == DialogInterface.BUTTON_POSITIVE) {if (mWifiP2pManager != null) {mWifiP2pManager.removeGroup(mChannel, new WifiP2pManager.ActionListener() {public void onSuccess() {if (DBG) Log.d(TAG, " remove group success");}public void onFailure(int reason) {if (DBG) Log.d(TAG, " remove group fail " + reason);}});}}}};//cancel connect dialog listenermCancelConnectListener = new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {if (which == DialogInterface.BUTTON_POSITIVE) {if (mWifiP2pManager != null) {mWifiP2pManager.cancelConnect(mChannel,new WifiP2pManager.ActionListener() {public void onSuccess() {if (DBG) Log.d(TAG, " cancel connect success");}public void onFailure(int reason) {if (DBG) Log.d(TAG, " cancel connect fail " + reason);}});}}}};//delete persistent group dialog listenermDeleteGroupListener = new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {if (which == DialogInterface.BUTTON_POSITIVE) {if (mWifiP2pManager != null) {if (mSelectedGroup != null) {if (DBG) Log.d(TAG, " deleting group " + mSelectedGroup.getGroupName());mWifiP2pManager.deletePersistentGroup(mChannel,mSelectedGroup.getNetworkId(),new WifiP2pManager.ActionListener() {public void onSuccess() {if (DBG) Log.d(TAG, " delete group success");}public void onFailure(int reason) {if (DBG) Log.d(TAG, " delete group fail " + reason);}});mSelectedGroup = null;} else {if (DBG) Log.w(TAG, " No selected group to delete!" );}}} else if (which == DialogInterface.BUTTON_NEGATIVE) {if (DBG) {Log.d(TAG, " forgetting selected group " + mSelectedGroup.getGroupName());}mSelectedGroup = null;}}};setHasOptionsMenu(true);final PreferenceScreen preferenceScreen = getPreferenceScreen();preferenceScreen.removeAll();preferenceScreen.setOrderingAsAdded(true);mThisDevicePref = new Preference(getActivity());mThisDevicePref.setPersistent(false);mThisDevicePref.setSelectable(false);preferenceScreen.addPreference(mThisDevicePref);mPeersGroup = new PreferenceCategory(getActivity());mPeersGroup.setTitle(R.string.wifi_p2p_peer_devices);preferenceScreen.addPreference(mPeersGroup);mPersistentGroup = new PreferenceCategory(getActivity());mPersistentGroup.setTitle(R.string.wifi_p2p_remembered_groups);preferenceScreen.addPreference(mPersistentGroup);super.onActivityCreated(savedInstanceState);}

2.WifiP2pSettings工作流程
1)WIFI_P2P_STATE_CHANGED_ACTION处理流程
打开WifiP2pSettings后,首先要等待 WIFI_P2P_STATE_CHANGED_ACTION广播以判断P2P功能是否正常启动。相应的处理函数如下所示:
android-5.1/packages/apps/Settings/src/com/android/settings/wifi/p2p/WifiP2pSettings.java

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {@Overridepublic 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();//如果搜索到新的P2P设备,则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 (networkInfo.isConnected()) {if (DBG) Log.d(TAG, "Connected");} else if (mLastGroupFormed != true) {//start a search when we are disconnected//but not on group removed broadcast eventstartSearch();   //如果没有加入某个P2P组,则重新发起设备扫描}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);}}}};
    private void handleP2pStateChanged() {updateSearchMenu(false);//该函数将触发WifiP2pSettings的onCreateOptionsMenu被调用mThisDevicePref.setEnabled(mWifiP2pEnabled);mPeersGroup.setEnabled(mWifiP2pEnabled);mPersistentGroup.setEnabled(mWifiP2pEnabled);}

用户下一步要做的事情就是主动搜索周围的P2P设备。Android原生代码中的WifiP2pSettings界面下方有两个按钮,分别是SEARCH和RENAME,分别用于搜索周围的P2P Device和更改本机的P2P设备名。
当P2P功能正常启用后(即上述代码中的mWifiP2pEnabled为true时),这两个按钮将被使能。此后,用户就可单击SEARCH按钮以搜索周围的P2P设备。该按钮对应的函数是startSearch。

    private void startSearch() {if (mWifiP2pManager != null && !mWifiP2pSearching) {//discoverPeers将搜索周围的P2P设备mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {public void onSuccess() {}public void onFailure(int reason) {if (DBG) Log.d(TAG, " discover fail " + reason);}});}}

当WPAS完成搜索后, WIFI_P2P_PEERS_CHANGED_ACTION广播将被发送。对该广播的处理参考onReceive函数。startSearch还将触发系统发送 WIFI_P2P_DISCOVERY_CHANGED_ACTION广播,WifiP2pSettings将根据该广播携带的信息来更新SEARCH按钮的界面:如果P2P Discovery启动成功(即状态变为 WIFI_P2P_DISCOVERY_STARTED),则SEARCH按钮名称显示为Searching,否则该按钮显示为Search For Devices。
当系统搜索到新的P2P设备后,WIFI_P2P_PEERS_CHANGED_ACTION广播将被发送,而WifiP2pSettings对于该广播的处理就是调用WifiP2pManager的requestPeers来获取系统保存的P2P设备信息列表
系统中所有的P2P设备信息将通过PeerListener接口类的onPeersAvailable函数返回给WifiP2pSettings:

    public void onPeersAvailable(WifiP2pDeviceList peers) {if (DBG) Log.d(TAG, "Requested peers are available");//系统中所有的P2P设备信息都保存在这个类型为WifiP2pDeviceList的peers对象中mPeers = peers;handlePeersChanged();}
    private void handlePeersChanged() {mPeersGroup.removeAll();//mPeersGroup类型为PreferenceGroup,属于UI相关的类mConnectedDevices = 0;if (DBG) Log.d(TAG, "List of available peers");for (WifiP2pDevice peer: mPeers.getDeviceList()) {if (DBG) Log.d(TAG, "-> " + peer);//WifiP2pPeer是Preference的子类,它和UI相关mPeersGroup.addPreference(new WifiP2pPeer(getActivity(), peer));if (peer.status == WifiP2pDevice.CONNECTED) mConnectedDevices++;}if (DBG) Log.d(TAG, " mConnectedDevices " + mConnectedDevices);}

在该函数中,WifiP2pDeviceList中保存的每一个WifiP2pDevice信息将作为一个Preference项添加到mPeersGroup中并显示在UI界面上。
接下来用户就可在界面中选择某个P2P设备并与之连接,这个步骤由onPreferenceTreeClick函数来完成。

    public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {if (preference instanceof WifiP2pPeer) {mSelectedWifiPeer = (WifiP2pPeer) preference;//获取用户指定的那一个WifiP2pPeer项if (mSelectedWifiPeer.device.status == WifiP2pDevice.CONNECTED) {showDialog(DIALOG_DISCONNECT);//如果已经和该设备连接,则判断是否需要与之断开连接} 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设备支持的WSC配置方法,优先考虑PBCif (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设备发起连接。注意,目标设备信息保存在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);}

当系统完成和P2P设备的连接后,WifiP2pSettings将收到 WIFI_P2P_CONNECTION_CHANGED_ACTION 广播,对应的代码见onReceive

WifiP2pSettings工作流程相关推荐

  1. Android之wifi工作流程

    Android Wifi的工作流程 一.WIFI工作相关部分 Wifi 网卡状态 1.    WIFI_STATE_DISABLED:WIFI网卡不可用 2.    WIFI_STATE_DISABL ...

  2. GPU—加速数据科学工作流程

    GPU-加速数据科学工作流程 GPU-ACCELERATE YOUR DATA SCIENCE WORKFLOWS 传统上,数据科学工作流程是缓慢而繁琐的,依赖于cpu来加载.过滤和操作数据,训练和部 ...

  3. python爬虫之Scrapy框架的post请求和核心组件的工作 流程

    python爬虫之Scrapy框架的post请求和核心组件的工作 流程 一 Scrapy的post请求的实现 在爬虫文件中的爬虫类继承了Spider父类中的start_urls,该方法就可以对star ...

  4. Blender+SP+UE5游戏艺术工作流程学习

    Blender到虚幻引擎5 Blender游戏艺术 Blender for Game Art 你会学到: 如何在Blender中创建三维模型 UV如何展开和布局 如何在Substance Painte ...

  5. Revit: Twinmotion工作流程学习

    Revit: Twinmotion Workflow MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz,2 Ch 技能等级:中级|语言:英语+中英文字幕(根据原英文字幕机译 ...

  6. iOS应用模块化的思考及落地方案(一)模块的划分及模块化工作流程

    1.0 什么是模块化 很多关于重构及设计模式的介绍中,经常提到的几个词语是复用及解耦. 模块化之所以被提出,也更多是为了解决这几个问题. 复用可以减少重复造轮子的情况,很容易理解的是,我们经常使用的g ...

  7. travis ci_如何使用Travis CI和GitHub进行Web开发工作流程

    travis ci by Vijayabharathi Balasubramanian 通过Vijayabharathi Balasubramanian 如何使用Travis CI和GitHub进行W ...

  8. Nginx源码分析:master/worker工作流程概述

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> Nginx的master与worker工作模式 在生成环境中的Nginx启动模式基本都是以m ...

  9. Scrapy框架的概念、作用和工作流程

    1. scrapy的概念         Scrapy是一个Python编写的开源网络爬虫框架.它是一个被设计用于爬取网络数据.提取结构性数据的框架. Scrapy是一个为了爬取网站数据,提取结构性数 ...

最新文章

  1. 洛谷P2763 试题库问题
  2. 云计算登顶之后,亚马逊人工智能走上新征程
  3. 日本机器人实力大盘点,和Atlas的高调刷屏相比,日本机器人的默默崛起更让人忌惮...
  4. getchar getche getch的区别
  5. C# 调用Excel 出现服务器出现意外情况. (异常来自 HRESULT:0x80010105 (RPC_E_SERVERFAULT)
  6. 深度学习(十)keras学习笔记
  7. win10输入法切换快捷键怎么设置
  8. “山东土地集团杯”暨滨州市数据应用创新创业大赛正式启动!
  9. Sigma IDE现在支持Python无服务器Lambda函数!
  10. 爬虫-urlparse与urlsplit
  11. IoT:加密与安全:几种常用安全加密算法原理与用途解析
  12. 设置mybatis 的sql 打印
  13. c51汇编语言位操作,51单片机汇编语言教程之单片机位操作指令的详细资料说明...
  14. 网易邮箱显示服务器返回错误,企业退信的常见问题?
  15. 深入浅出了解AUTOSAR Adaptive平台
  16. Phalcon入坑必须知道的功能《Phalcon入坑指南系列 二》
  17. 实时训练Real-Time Training 教程
  18. CSDN复制文章到Word保留样式方法
  19. 层次分析法实例:选择旅游目的地
  20. Tuscany插件的安装

热门文章

  1. ADB 查看 crash log
  2. Android Studio 中修改versionCode跟versionName (更新版本)
  3. 机器学习入门(01)— 感知机概念、实现、局限性以及多层感知机
  4. Await, and UI, and deadlocks! Oh my!
  5. [置顶] 我的GB28181标准开发里程碑——基于eXosip的IPC端与SPVMN注册成功
  6. oracle创建DBLink连接
  7. CentOS 6.3 安装 samba 共享
  8. linux access函数判断文件存取权限
  9. Asp.net控件开发学习笔记(三)-控件开发基础
  10. 计算机基础2多媒体,《计算机基础》第2章-多媒体技术.pptx