Android WIFI 分析(二)
本文介绍Wifi 分析线路二:在Setting中打开WiFi功能、扫描网络以及连接网络的流程。
WifiSettings 无线网络设置界面
WifiEnabler 相当于无线网络设置开关
WifiDialog 显示的无线网络配置信息由WifiConfigController 来控制和管理
Scanner 用于处理和无线网络扫描相关的工作
1、Settings 操作
无线网络设置界面UI 初始化过程中,WifiSettings 的onActivityCreated() 方法被调用:
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); mWifiTracker =
new WifiTracker(getActivity(), this, mBgThread.getLooper(), true, true, false);
mWifiManager = mWifiTracker.getManager();
}
WifiTracker 构造函数调用:
WifiTracker(Context context, WifiListener wifiListener, Looper workerLooper,
boolean includeSaved, boolean includeScans, boolean includePasspoints,
WifiManager wifiManager, ConnectivityManager connectivityManager,
Looper currentLooper) {
//添加多个广播事件,在startTracker() 方法中进行注册
mFilter = new IntentFilter();
mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); mNetworkRequest = new NetworkRequest.Builder()
.clearCapabilities()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
}
WifiSettings 的onStart() 方法创建WifiEnabler:
public void onStart() {
// On/off switch is hidden for Setup Wizard (returns null)
mWifiEnabler = createWifiEnabler();
} WifiEnabler createWifiEnabler() {
final SettingsActivity activity = (SettingsActivity) getActivity();
return new WifiEnabler(activity, activity.getSwitchBar());
}
WifiEnabler 的构造函数,添加广播事件:
public WifiEnabler(Context context, SwitchBar switchBar) {
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
//添加三个广播事件
mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
// The order matters! We really should not depend on this. :(
mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); setupSwitchBar();
}
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() 的方法中被注册:
public void onResume() {
final Activity activity = getActivity();
if (mWifiEnabler != null) {
mWifiEnabler.resume(activity); //调用WifiEnabler 类
} mWifiTracker.startTracking(); //调用framework WifiTracker 类
activity.invalidateOptionsMenu();
}
WifiEnabler 类的resume() 方法如下:
public void resume(Context context) {
mContext = context;
// Wi-Fi state is sticky, so just let the receiver update UI
mContext.registerReceiver(mReceiver, mIntentFilter); //注册构造函数中添加的三个广播事件
if (!mListeningToOnSwitchChange) {
mSwitchBar.addOnSwitchChangeListener(this);
mListeningToOnSwitchChange = true;
}
}
WifiTracker 类的startTracking() 方法如下:
/**
* Start tracking wifi networks.
* Registers listeners and starts scanning for wifi networks. If this is not called
* then forceUpdate() must be called to populate getAccessPoints().
*/
public void startTracking() {
resumeScanning();
if (!mRegistered) {
mContext.registerReceiver(mReceiver, mFilter); //注册构造函数中添加的广播事件
// NetworkCallback objects cannot be reused. http://b/20701525 .
mNetworkCallback = new WifiTrackerNetworkCallback();
mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
}
}
WifiEnabler 处理较多的及时WIFI_STATE_CHANGED_ACTION 广播,根据此广播信息更新Switch 的界面。
2、启用WIFI 功能
WifiEnabler 实现了SwitchBar 的onSwitchChangeListener 接口,故用户点击事件将触发WifiEnabler 的onSwitchChanged() 方法:
public void onSwitchChanged(Switch switchView, boolean isChecked) {
// Disable tethering if enabling Wifi
if (mayDisableTethering(isChecked)) {
mWifiManager.setWifiApEnabled(null, false);
}
}
WifiManager 的setWifiApEnabled() 方法将触发WifiService 开展一系列的动作,在此过程中,WifiManager 会通过发送广播的方法向外界发布一些信息,所以需重点关注广播事件的处理。
WifiTracker 的广播接收对象的处理:
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN));
} else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) ||
WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) ||
WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS); //发送更新无线网络列表消息
} else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
WifiManager.EXTRA_NETWORK_INFO);
mConnected.set(info.isConnected());
mMainHandler.sendEmptyMessage(MainHandler.MSG_CONNECTED_CHANGED);
mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_NETWORK_INFO, info)
.sendToTarget();
}
}
};
WifiEnabler 的广播接收对象的处理:
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
handleWifiStateChanged(intent.getIntExtra(
WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
} else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
if (!mConnected.get()) {
handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState)
intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
}
} else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
WifiManager.EXTRA_NETWORK_INFO);
mConnected.set(info.isConnected());
handleStateChanged(info.getDetailedState());
}
}
};
1) 触发扫描
当WIFI 功能被启用时,将收到WIFI_STATE_CHANGED_ACTION 广播,该广播的处理函数是WifiTracker 的updateWifiState() 方法:
private void updateWifiState(int state) {
mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_WIFI_STATE, state, 0).sendToTarget();
} //向内部WrokHandler 对象发送消息
MSG_UPDATE_WIFI_STATE 的处理:
case MSG_UPDATE_WIFI_STATE:
if (msg.arg1 == WifiManager.WIFI_STATE_ENABLED) {
if (mScanner != null) {
// We only need to resume if mScanner isn't null because
// that means we want to be scanning.
mScanner.resume(); //启动扫描
}
} else {
mLastInfo = null;
mLastNetworkInfo = null;
if (mScanner != null) {
mScanner.pause();
}
}
mMainHandler.obtainMessage(MainHandler.MSG_WIFI_STATE_CHANGED, msg.arg1, 0)
.sendToTarget(); //向内部MainHandler 对象发送消息
break;
Scanner 也是WifiTracker 内部定义的一个Handler:
class Scanner extends Handler {
static final int MSG_SCAN = 0; void resume() {
if (!hasMessages(MSG_SCAN)) {
sendEmptyMessage(MSG_SCAN);
}
} @Override
public void handleMessage(Message message) {
if (message.what != MSG_SCAN) return;
if (mWifiManager.startScan()) { //发起扫描
mRetry = 0;
} else if (++mRetry >= 3) { //扫描失败
mRetry = 0;
if (mContext != null) {
Toast.makeText(mContext, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();
}
return;
}
sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS); //每1秒发起一次扫描
}
}
2) 更新AP 列表
如果WPAS 扫描完毕,则WifiTracker 将收到SCAN_RESULTS_AVAILABLE_ACTION 广播,发送消息MSG_UPDATE_ACCESS_POINTS,WorkHandler 对此消息的处理如下:
case MSG_UPDATE_ACCESS_POINTS:
updateAccessPoints();
break;
继而调用updateAccessPoints() 方法:
private void updateAccessPoints() {
final Collection<ScanResult> results = fetchScanResults(); //获取扫描结果
final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
// Pre-sort accessPoints to speed preference insertion
Collections.sort(accessPoints); //创建AP 列表
mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED); //向MainHandler 发送MSG_ACCESS_POINT_CHANGED
3) 加入目标无线网络
从列表中选择加入某个无线网络,处理用户选择AP 事件的方法是WifiSettings 的onPreferenceTreeClick() 方法:
public boolean onPreferenceTreeClick(Preference preference) {
if (preference instanceof LongPressAccessPointPreference) {
mSelectedAccessPoint = ((LongPressAccessPointPreference) preference).getAccessPoint();
/** Bypass dialog for unsecured, unsaved, and inactive networks */
if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE &&
!mSelectedAccessPoint.isSaved() && !mSelectedAccessPoint.isActive()) { //对于没有安全设置的无线网络,直接连接它即可
mSelectedAccessPoint.generateOpenNetworkConfig();
connect(mSelectedAccessPoint.getConfig());
} else if (mSelectedAccessPoint.isSaved()) {
showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_VIEW); //弹出无线密码输入框
} else {
showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);
}
} else if (preference == mAddPreference) {
onAddNetworkPressed();
}
}
当用户设置完目标无线网络(例如设置密码)后,点击“连接”按钮,将触发WifiSettings 的submit() 方法被调用:
/* package */ void submit(WifiConfigController configController) {
final WifiConfiguration config = configController.getConfig();
if (config == null) {
......
} else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) {
mWifiManager.save(config, mSaveListener);
} else {
mWifiManager.save(config, mSaveListener);
if (mSelectedAccessPoint != null) { // Not an "Add network"
connect(config); //连接目标无线网络
}
}
mWifiTracker.resumeScanning();
}
至此,后续的工作就是等待并处理广播事件,如果一切顺利,将接收一个NETWORK_STATE_CHANGED_ACTION 广播事件以告知手机成功加入目标无线网络。
和WifiManager 交互的几个重要函数以作下面分析重点:
setWifiEnabled():启用WIFI 功能
startScanActive():启动AP 扫描
connect():连接至目标AP
Android WIFI 分析(二)的更多相关文章
- Android WIFI 分析(一)
本文基于<深入理解Android WiFi NFC和GPS 卷>和 Android N 代码结合分析 WifiService 是 Frameworks中负责wifi功能的核心服务,它主 ...
- Android Telephony分析(二) ---- RegistrantList详解
前言 本文主要讲解RegistrantList的原理,以及如何快速分析RegistrantList相关的代码流程.在Telephony模块中,在RIL.Tracker(ServiceStateTrac ...
- Android 短信模块分析(二) MMS中四大组件核心功能详解
接下来的分析先从MMS中四大组件(Activity ,BroadCastReceiver,Service,ContentProvider),也是MMS中最核心的部分入手: 一. Activity 1 ...
- Android测试分析二
什么是android测试,分为黑盒测试和白盒测试. 黑盒就是测试人员看不到代码的,针对需求而进行的一系列测试动作,看代码所展现出来的效果是否和需求一样,或者有什么意外的情况没有处理等,一般开发交给测试 ...
- Android Binder分析二:Natvie Service的注冊
这一章我们通过MediaPlayerService的注冊来说明怎样在Native层通过binder向ServiceManager注冊一个service,以及client怎样通过binder向Servi ...
- Android Telephony分析(六) ---- 接口扩展(实践篇)
本文将结合前面五篇文章所讲解的知识,综合起来,实现一个接口扩展的功能.如果还没有阅读过前面五篇文章的内容,请先阅读:<Android Telephony分析(一) — Phone详解 >& ...
- Android Telephony分析(三) ---- RILJ详解
前言 本文主要讲解RILJ工作原理,以便更好地分析代码,分析业务的流程.这里说的RILJ指的是RIL.java (frameworks\opt\telephony\src\java\com\andro ...
- android wifi ANR问题分析总结
android wifi ANR问题分析总结 1 看看main进程阻塞在那里? 2 调用关系的函数阻塞在那里? 3 最终阻塞函数的阻塞前的log以及状态
- Android多线程分析之二:Thread的实现
Android多线程分析之二:Thread的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多线程分析之一 ...
随机推荐
- 前端设计师也有必要学习seo,推荐一个seo博客
做前端设计师有一段时间了,现在越来越觉得作为一个前端设计师,必须要懂一些seo的知识. 因为公司的seo们,总是在网站做好以后,提出各种各样的网站修改的需求. 如果前端设计师,能够了解一些基本的seo ...
- R连接Mysql时,中文显示为问号的解决方案
1.打开Mysql安装目录下的my.ini文件,将其中的default-character-set= 均设置为GBK 2.在管理工具——数据源(ODBC)中将创建好的数据源作如下设置:
- 用gulp建立自动工具,完成软件的编译、测试、打包和发布流程
gulp以task的形式组织任务. 在每一个任务中,从gulp.src()指定文件源头开始,经过一系列pipe管道处理, 最后结果保存到gulp.dest指定的目录中,(或输出到stream) 任务的 ...
- strace 解决库依赖问题
解决库依赖问题 starce 的另一个用处是解决和动态库相关的问题.当对一个可执行文件运行ldd时,它会告诉你程序使用的动态库和找到动态库的位置.但是如果你正在使用一个比较老 的glibc版本(2.2 ...
- DMA控制
1.S3C6410中DMA操作步骤 S3C6410中DMA操作步骤:1.决定使用安全DMAC(SDMAC)还是通用DMAC(DMAC):2.开始相应DMAC的系统时钟,并关闭另外一组的时钟(系统默认开 ...
- 重新介绍 JavaScript
简介 为什么需要这个重新介绍呢?因为 JavaScript 已经完全可以被称为世界上被误解最严重的编程语言了.虽然它被当做玩具来用,但是藏在让人迷惑的简单表象下面的,是强大的语言特性.从2005年,一 ...
- Docker Day1 & 2
1. Docker Basic 安装docker(在/etc/selinux/config文件中设置selinux=disabled,否则安装时会报错) curl -ssL http://get.do ...
- 使用es6的set和map实现数组去重复
var set = new Set();var arr = [1, 2, 3, 3, 2, 1];arr.map(val => set.add(val));// arr.map(function ...
- NHibernate系列文章目录
第一章:NHibernate基础 NHibernate介绍 第一个NHibernate工程 简单的增删改查询 运行时监控 NHibernate配置 数据类型映射 Get/Load方法 NHiberna ...
- Linux内核分析 第二周
Linux内核分析——完成一个简单的时间片轮转多道程序内核代码 张潇月+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-100 ...