本文介绍Wifi 分析线路二:在Setting中打开WiFi功能、扫描网络以及连接网络的流程。

WifiSettings 无线网络设置界面

WifiEnabler 相当于无线网络设置开关

WifiDialog 显示的无线网络配置信息由WifiConfigController 来控制和管理

Scanner 用于处理和无线网络扫描相关的工作

1、Settings 操作

无线网络设置界面UI 初始化过程中,WifiSettings 的onActivityCreated() 方法被调用:

  1. public void onActivityCreated(Bundle savedInstanceState) {
  2. super.onActivityCreated(savedInstanceState);
  3.  
  4. mWifiTracker =
  5. new WifiTracker(getActivity(), this, mBgThread.getLooper(), true, true, false);
  6. mWifiManager = mWifiTracker.getManager();
  7. }

WifiTracker 构造函数调用:

  1. WifiTracker(Context context, WifiListener wifiListener, Looper workerLooper,
  2. boolean includeSaved, boolean includeScans, boolean includePasspoints,
  3. WifiManager wifiManager, ConnectivityManager connectivityManager,
  4. Looper currentLooper) {
  5.     //添加多个广播事件,在startTracker() 方法中进行注册
  6. mFilter = new IntentFilter();
  7. mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
  8. mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
  9. mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
  10. mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
  11. mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
  12. mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
  13. mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
  14.  
  15. mNetworkRequest = new NetworkRequest.Builder()
  16. .clearCapabilities()
  17. .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
  18. .build();
  19. }

WifiSettings 的onStart() 方法创建WifiEnabler:

  1. public void onStart() {
  2. // On/off switch is hidden for Setup Wizard (returns null)
  3. mWifiEnabler = createWifiEnabler();
  4. }
  5.  
  6. WifiEnabler createWifiEnabler() {
  7. final SettingsActivity activity = (SettingsActivity) getActivity();
  8. return new WifiEnabler(activity, activity.getSwitchBar());
  9. }

WifiEnabler 的构造函数,添加广播事件:

  1. public WifiEnabler(Context context, SwitchBar switchBar) {
  2. mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
  3.      //添加三个广播事件
  4. mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
  5. // The order matters! We really should not depend on this. :(
  6. mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
  7. mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
  8.  
  9. setupSwitchBar();
  10. }

WIFI_STATE_CHANGED_ACTION:反映WiFi 功能所对应的状态,包括WIFI_STATE_DISABLED(Wifi 功能已被关闭)、WIFI_STATE_DISABLING(Wifi 功能正在关闭中)、WIFI_STATE_ENABLED(Wifi 功能已被打开)、WIFI_STATE_ENABLING(Wifi 功能正在打开中)、WIFI_STATE_UNKNOWN(Wifi 功能状态未知)。

SUPPLICANT_STATE_CHANGED_ACTION:表示WPAS 的状态发生了变化。

NETWORK_STATE_CHANGED_ACTION:表示WIFI 连接状态发生变化,其携带的信息一般是NetworkInfo 对象。

WifiSettings 和 WifiEnabler 的设置的广播接收对象在onResume() 的方法中被注册:

  1. public void onResume() {
  2. final Activity activity = getActivity();
  3. if (mWifiEnabler != null) {
  4. mWifiEnabler.resume(activity); //调用WifiEnabler 类
  5. }
  6.  
  7. mWifiTracker.startTracking(); //调用framework WifiTracker 类
  8. activity.invalidateOptionsMenu();
  9. }

WifiEnabler 类的resume() 方法如下:

  1. public void resume(Context context) {
  2. mContext = context;
  3. // Wi-Fi state is sticky, so just let the receiver update UI
  4. mContext.registerReceiver(mReceiver, mIntentFilter); //注册构造函数中添加的三个广播事件
  5. if (!mListeningToOnSwitchChange) {
  6. mSwitchBar.addOnSwitchChangeListener(this);
  7. mListeningToOnSwitchChange = true;
  8. }
  9. }

WifiTracker 类的startTracking() 方法如下:

  1. /**
  2. * Start tracking wifi networks.
  3. * Registers listeners and starts scanning for wifi networks. If this is not called
  4. * then forceUpdate() must be called to populate getAccessPoints().
  5. */
  6. public void startTracking() {
  7. resumeScanning();
  8. if (!mRegistered) {
  9. mContext.registerReceiver(mReceiver, mFilter); //注册构造函数中添加的广播事件
  10. // NetworkCallback objects cannot be reused. http://b/20701525 .
  11. mNetworkCallback = new WifiTrackerNetworkCallback();
  12. mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
  13. }
  14. }

WifiEnabler 处理较多的及时WIFI_STATE_CHANGED_ACTION 广播,根据此广播信息更新Switch 的界面。

2、启用WIFI 功能

WifiEnabler 实现了SwitchBar 的onSwitchChangeListener 接口,故用户点击事件将触发WifiEnabler 的onSwitchChanged() 方法:

  1. public void onSwitchChanged(Switch switchView, boolean isChecked) {
  2. // Disable tethering if enabling Wifi
  3. if (mayDisableTethering(isChecked)) {
  4. mWifiManager.setWifiApEnabled(null, false);
  5. }
  6. }

WifiManager 的setWifiApEnabled() 方法将触发WifiService 开展一系列的动作,在此过程中,WifiManager 会通过发送广播的方法向外界发布一些信息,所以需重点关注广播事件的处理。

WifiTracker 的广播接收对象的处理:

  1. final BroadcastReceiver mReceiver = new BroadcastReceiver() {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. String action = intent.getAction();
  5. if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
  6. updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
  7. WifiManager.WIFI_STATE_UNKNOWN));
  8. } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) ||
  9. WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) ||
  10. WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
  11. mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS); //发送更新无线网络列表消息
  12. } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
  13. NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
  14. WifiManager.EXTRA_NETWORK_INFO);
  15. mConnected.set(info.isConnected());
  16. mMainHandler.sendEmptyMessage(MainHandler.MSG_CONNECTED_CHANGED);
  17. mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
  18. mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_NETWORK_INFO, info)
  19. .sendToTarget();
  20. }
  21. }
  22. };

WifiEnabler 的广播接收对象的处理:

  1. private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. String action = intent.getAction();
  5. if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
  6. handleWifiStateChanged(intent.getIntExtra(
  7. WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
  8. } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
  9. if (!mConnected.get()) {
  10. handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState)
  11. intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
  12. }
  13. } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
  14. NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
  15. WifiManager.EXTRA_NETWORK_INFO);
  16. mConnected.set(info.isConnected());
  17. handleStateChanged(info.getDetailedState());
  18. }
  19. }
  20. };

1) 触发扫描

当WIFI 功能被启用时,将收到WIFI_STATE_CHANGED_ACTION 广播,该广播的处理函数是WifiTracker 的updateWifiState() 方法:

  1. private void updateWifiState(int state) {
  2. mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_WIFI_STATE, state, 0).sendToTarget();
  3. } //向内部WrokHandler 对象发送消息

MSG_UPDATE_WIFI_STATE 的处理:

  1. case MSG_UPDATE_WIFI_STATE:
  2. if (msg.arg1 == WifiManager.WIFI_STATE_ENABLED) {
  3. if (mScanner != null) {
  4. // We only need to resume if mScanner isn't null because
  5. // that means we want to be scanning.
  6. mScanner.resume(); //启动扫描
  7. }
  8. } else {
  9. mLastInfo = null;
  10. mLastNetworkInfo = null;
  11. if (mScanner != null) {
  12. mScanner.pause();
  13. }
  14. }
  15. mMainHandler.obtainMessage(MainHandler.MSG_WIFI_STATE_CHANGED, msg.arg1, 0)
  16. .sendToTarget(); //向内部MainHandler 对象发送消息
  17. break;

Scanner 也是WifiTracker 内部定义的一个Handler:

  1. class Scanner extends Handler {
  2. static final int MSG_SCAN = 0;
  3.  
  4. void resume() {
  5. if (!hasMessages(MSG_SCAN)) {
  6. sendEmptyMessage(MSG_SCAN);
  7. }
  8. }
  9.  
  10. @Override
  11. public void handleMessage(Message message) {
  12. if (message.what != MSG_SCAN) return;
  13. if (mWifiManager.startScan()) { //发起扫描
  14. mRetry = 0;
  15. } else if (++mRetry >= 3) { //扫描失败
  16. mRetry = 0;
  17. if (mContext != null) {
  18. Toast.makeText(mContext, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();
  19. }
  20. return;
  21. }
  22. sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS); //每1秒发起一次扫描
  23. }
  24. }

2) 更新AP 列表

如果WPAS 扫描完毕,则WifiTracker 将收到SCAN_RESULTS_AVAILABLE_ACTION 广播,发送消息MSG_UPDATE_ACCESS_POINTS,WorkHandler 对此消息的处理如下:

  1. case MSG_UPDATE_ACCESS_POINTS:
  2. updateAccessPoints();
  3. break;

继而调用updateAccessPoints() 方法:

  1. private void updateAccessPoints() {
  2. final Collection<ScanResult> results = fetchScanResults(); //获取扫描结果
  3. final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
  4. // Pre-sort accessPoints to speed preference insertion
  5. Collections.sort(accessPoints); //创建AP 列表
  6. mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED); //向MainHandler 发送MSG_ACCESS_POINT_CHANGED

3) 加入目标无线网络

从列表中选择加入某个无线网络,处理用户选择AP 事件的方法是WifiSettings 的onPreferenceTreeClick() 方法:

  1. public boolean onPreferenceTreeClick(Preference preference) {
  2. if (preference instanceof LongPressAccessPointPreference) {
  3. mSelectedAccessPoint = ((LongPressAccessPointPreference) preference).getAccessPoint();
  4. /** Bypass dialog for unsecured, unsaved, and inactive networks */
  5. if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE &&
  6. !mSelectedAccessPoint.isSaved() && !mSelectedAccessPoint.isActive()) { //对于没有安全设置的无线网络,直接连接它即可
  7. mSelectedAccessPoint.generateOpenNetworkConfig();
  8. connect(mSelectedAccessPoint.getConfig());
  9. } else if (mSelectedAccessPoint.isSaved()) {
  10. showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_VIEW); //弹出无线密码输入框
  11. } else {
  12. showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);
  13. }
  14. } else if (preference == mAddPreference) {
  15. onAddNetworkPressed();
  16. }
  17. }

当用户设置完目标无线网络(例如设置密码)后,点击“连接”按钮,将触发WifiSettings 的submit() 方法被调用:

  1. /* package */ void submit(WifiConfigController configController) {
  2. final WifiConfiguration config = configController.getConfig();
  3. if (config == null) {
  4. ......
  5. } else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) {
  6. mWifiManager.save(config, mSaveListener);
  7. } else {
  8. mWifiManager.save(config, mSaveListener);
  9. if (mSelectedAccessPoint != null) { // Not an "Add network"
  10. connect(config); //连接目标无线网络
  11. }
  12. }
  13. mWifiTracker.resumeScanning();
  14. }

至此,后续的工作就是等待并处理广播事件,如果一切顺利,将接收一个NETWORK_STATE_CHANGED_ACTION 广播事件以告知手机成功加入目标无线网络。

和WifiManager 交互的几个重要函数以作下面分析重点:

setWifiEnabled():启用WIFI 功能

startScanActive():启动AP 扫描

connect():连接至目标AP

Android WIFI 分析(二)的更多相关文章

  1. Android WIFI 分析(一)

    本文基于<深入理解Android WiFi NFC和GPS 卷>和 Android N 代码结合分析   WifiService 是 Frameworks中负责wifi功能的核心服务,它主 ...

  2. Android Telephony分析(二) ---- RegistrantList详解

    前言 本文主要讲解RegistrantList的原理,以及如何快速分析RegistrantList相关的代码流程.在Telephony模块中,在RIL.Tracker(ServiceStateTrac ...

  3. Android 短信模块分析(二) MMS中四大组件核心功能详解

    接下来的分析先从MMS中四大组件(Activity ,BroadCastReceiver,Service,ContentProvider),也是MMS中最核心的部分入手: 一. Activity  1 ...

  4. Android测试分析二

    什么是android测试,分为黑盒测试和白盒测试. 黑盒就是测试人员看不到代码的,针对需求而进行的一系列测试动作,看代码所展现出来的效果是否和需求一样,或者有什么意外的情况没有处理等,一般开发交给测试 ...

  5. Android Binder分析二:Natvie Service的注冊

    这一章我们通过MediaPlayerService的注冊来说明怎样在Native层通过binder向ServiceManager注冊一个service,以及client怎样通过binder向Servi ...

  6. Android Telephony分析(六) ---- 接口扩展(实践篇)

    本文将结合前面五篇文章所讲解的知识,综合起来,实现一个接口扩展的功能.如果还没有阅读过前面五篇文章的内容,请先阅读:<Android Telephony分析(一) — Phone详解 >& ...

  7. Android Telephony分析(三) ---- RILJ详解

    前言 本文主要讲解RILJ工作原理,以便更好地分析代码,分析业务的流程.这里说的RILJ指的是RIL.java (frameworks\opt\telephony\src\java\com\andro ...

  8. android wifi ANR问题分析总结

    android wifi ANR问题分析总结 1 看看main进程阻塞在那里? 2 调用关系的函数阻塞在那里? 3 最终阻塞函数的阻塞前的log以及状态

  9. Android多线程分析之二:Thread的实现

    Android多线程分析之二:Thread的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处   在前文<Android多线程分析之一 ...

随机推荐

  1. fw: webdriver 那些坑

    http://www.cnblogs.com/huang0925/p/3384596.html 使用WebDriver遇到的那些坑   在做web项目的自动化端到端测试时主要使用的是Selenium ...

  2. 安装boost库(Windows)

    1. 下载 官网:http://www.boost.org/ 主页:https://sourceforge.net/projects/boost/ 当前最新版:V1.61.0 2. 编译 首先,生成b ...

  3. MySql绿色版下载,安装,配置详解

    下载完成之后解压,楼主用的版本是:mysql-5.7.15-winx64 解压完在根目录下建立一个data文件夹和my-default.ini my-default.ini里面的内容如下:(红色内容根 ...

  4. 用 pyvenv 创建几个不相互影响的python虚拟环境

    IN MY UBUNTU python2的环境控制: sudo apt-get install virtualenv 创建: virtualenv --no-site-packages  [环境搭建目 ...

  5. oracle计算是否是同一周

    函数已经解决跨年问题 select to_char(date'2016-12-31','iW') from dual; select to_char(date'2017-01-01','iW') fr ...

  6. Java集合类简单总结(重学)

    java集合类简介(重学) 一.Collection(集合).Map接口两者应该是平行关系吧. 1.Map介绍 Map是以键值(key-value)对来存放的,2个值.通过key来找到value(例: ...

  7. jsp+servlet+mysql 实现简单的银行登录转账功能

    jsp+servlet+mysql 实现简单的银行登录转账功能 [前期的准备] html(登录界面),servlet(处理业务逻辑),jsp(主要实现界面),mysql(实现与数据库的简单的交互)先从 ...

  8. float、double的有效位数

    Java中的浮点类型有两类,分别是float和double类型,其中float取_7__位有效数据,double取_15__位有效数据

  9. SQL数据库与excel表格之间的数据 导入

  10. Git 操作本地分支与远程分支

    1 查看本地分支 git branch 2 查看远程分支 git branch -a 3 新建远程分支 git checkout -b developr git push origin develop ...