前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android4.4.2源码分析之WiFi模块(三)

Android4.4.2源码分析之WiFi模块(三)

作者头像
fanfan
发布2022-05-07 14:49:39
7980
发布2022-05-07 14:49:39
举报
文章被收录于专栏:编程思想之路编程思想之路

参考博文

Android4.4.2源码分析之WiFi模块(一)

Android4.4.2源码分析之WiFi模块(二)

获取到WiFi列表后就是对WiFi进行连接,本博文分析WiFi列表的点击事件

Wifi列表中存有四中WiFi

  • 已连接WiFi
  • 未连接也无需输入密码的WiFi(程序不会对该WiFi进行保存)
  • 未连接但需要输入密码而且已保存的WiFi
  • 未连接但需要输入密码而且未保存的WiFi

分情况进行分析,

1,已连接的WiFi,点击弹出dialog显示WiFi信息

除了第二种情况无需密码的WiFi点击时直接连接,其他三种情况的点击事件的处理均是弹出dialog,只不过是根据不同情况去加载布局,说一下源码的实现思路,如果想做出这种效果可以增加代码的复用性可以参考源码实现思路。

showDialog时弹出WiFidialog对话框,对话框有title,content,以及button,在构造WiFidialog时会传入listener对button的事件进行处理,所以对于button的点击事件在WiFiSettings中进行处理。在WiFiDialog的onCreate方法中会调用如下代码

代码语言:javascript
复制
mController = new WifiConfigController(this, mView, mAccessPoint, mEdit);

创建出WifiConfigController对象,并在wifiConfigController中进行title以及content以及button内容的显示。对于content的显示为动态添加的布局,每次加载dialog时会去判断所要加载的信息是否存在,如果存在就调用addRow(。。)加载布局,addRow方法内部的实现如下:

代码语言:javascript
复制
 private void addRow(ViewGroup group, int name, String value) {
        View row = mConfigUi.getLayoutInflater().inflate(R.layout.wifi_dialog_row, group, false);
        ((TextView) row.findViewById(R.id.name)).setText(name);
        ((TextView) row.findViewById(R.id.value)).setText(value);
        group.addView(row);
    }

在该方法中动态添加两个textview,并将其添加至dialog。

已连接WiFi点击时所显示的信息是最全的,以此为例,该dialog包括以下几种信息(至于密码输入框在第四种情况进行介绍)

  • 状态信息:状态信息的获取可通过AccessPoint.getState()进行获取,
代码语言:javascript
复制
mAccessPoint.getState();

但是在该类中只是对state进行获取,不对其进行赋值或者修改,state的赋值或者修改位于WifiSettings中,当接收到WifiManager.NETWORK_STATE_CHANGED_ACTION网络状态改变时的广播时,借助intent的值进行获取NetworkInfo实例,借助该实例可以获取到state

代码语言:javascript
复制
 NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
                    WifiManager.EXTRA_NETWORK_INFO);


......

...
//利用NetworkInfo实例获取到state,进而去更新WiFi的Javabean数据AccessPoint
info.getDetailedState()
  • 信号强度
代码语言:javascript
复制
int level = mAccessPoint.getLevel();

其方法内部又是怎么做的呢?

代码语言:javascript
复制
 int getLevel() {
        if (mRssi == Integer.MAX_VALUE) {
            return -1;
        }
        return WifiManager.calculateSignalLevel(mRssi, 4);
    }

这些代码开发者是可以直接调用的,而且开发者可以看到wifimanager.calculateSignalLevel(。。)方法的具体实现,大致分析一下就是通过将mRssi与所规定的最大值和最小值进行比较并进行简单运算后获取到一个int型的数值,根据int型的数值来加载对应的drawable,这也是表示WiFi的信号强度图标实现的原理。举个例子,利用imageview加载信号强度图标的做法如下:

第一,在drawable文件夹下创建xml文件wif_level.xml

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/wifi_level_0" android:maxLevel="0"/>
    <item android:drawable="@drawable/wifi_level_1" android:maxLevel="1"/>
    <item android:drawable="@drawable/wifi_level_2" android:maxLevel="2"/>
    <item android:drawable="@drawable/wifi_level_3" android:maxLevel="3"/>
</level-list>

第二,在布局文件中,对imageview控件的drawable属性引用刚才所创建的xml文件

第三,在Java代码中对imageview进行set

代码语言:javascript
复制
mWifiLevel.setImageLevel(WifiManager.calculateSignalLevel(mRssi,4))

至于对Rssi的获取可参考前两个博客

  • 连接速度
代码语言:javascript
复制
WifiInfo info = mAccessPoint.getInfo();
            if (info != null && info.getLinkSpeed() != -1) {
                ..........
            }

可以看出连接速度是通过WiFiinfo的实例来获取的,开发者可以通过调用如下代码获取实例

代码语言:javascript
复制
WifiInfo info = mWifiManager.getConnectionInfo();

获取到info后获取连接速度代码就如上所示了

  • 安全性
代码语言:javascript
复制
mAccessPoint.getSecurityString(false)

该方法内部是根据security来返回不同的字符串,归根结底还是要查找security是如何获取的

代码语言:javascript
复制
static int getSecurity(WifiConfiguration config) {
        if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
            return SECURITY_PSK;
        }
        if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
                config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
            return SECURITY_EAP;
        }
        return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE;
    }

security的获取借助于WifiConfiguration对象,config的获取参考博文二

  • IP地址
代码语言:javascript
复制
for(InetAddress a : config.linkProperties.getAddresses()) {
....
          a.getHostAddress();
.....
               }

源码中获取WiFi的ip地址的方式是借助wificonfig实例对象去获取,但是config的linkProperties字段对开发者是hide的,不过我们可以借助WiFiinfo的实例去获取到已经连接的WiFi的ip地址

代码语言:javascript
复制
info.getIpAddress();

以上信息大部分都是从AccessPont获取的,AccessPoint.java相当于存放WiFi的Javabean数据,但是对开发者是hide的,但开发者可以模拟AccessPoint去自己创建WiFi的Javabean数据的类

2,点击未连接无需密码的WiFi

点击该WiFi没有dialog弹出,直接进行WiFi的连接,

代码语言:javascript
复制
if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE &&
                    mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {
                mSelectedAccessPoint.generateOpenNetworkConfig();
                mWifiManager.connect(mSelectedAccessPoint.getConfig(), mConnectListener);

通过判断security属性来判断是否加密(security的来源是有Scanresult的capabilities决定的,可参考博文二),然后判断是否网络ID是否有效,如果以上两种条件均满足的话则可以调用WifiManager的connect()方法直接连接

3,点击未连接需要输入密码而且已保存的WiFi

代码语言:javascript
复制
 protected void generateOpenNetworkConfig() {
        if (security != SECURITY_NONE)
            throw new IllegalStateException();
        if (mConfig != null)
            return;
        mConfig = new WifiConfiguration();
        mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
        mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
    }

连接WiF调用的是WifiManager的connect方法,但该方法是隐藏的,在进行APP编程时无法直接调用,但可以调用mWifiManager.enableNetwork(int netId,boolean disableOthers)进行连接.

对于button的点击大体上分两种情况:

代码语言:javascript
复制
@Override
    public void onClick(DialogInterface dialogInterface, int button) {
        if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
            forget();//取消保存
        } else if (button == WifiDialog.BUTTON_SUBMIT) {
            if (mDialog != null) {
                submit(mDialog.getController());//连接
            }
        }
    }

对于取消保存只有WiFi在已保存的情况下才会出现,点击该按钮后会取消对WiFi的保存,即清除该WiFi的WiFiConfig信息

代码语言:javascript
复制
mWifiManager.forget(mSelectedAccessPoint.networkId, mForgetListener);

对于submit按钮,分保存(添加网络时)和连接

代码语言:javascript
复制
void submit(WifiConfigController configController) {

        final WifiConfiguration config = configController.getConfig();

        if (config == null) {
            if (mSelectedAccessPoint != null
                    && mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
                mWifiManager.connect(mSelectedAccessPoint.networkId,
                        mConnectListener);
            }
        } else if (config.networkId != INVALID_NETWORK_ID) {
            if (mSelectedAccessPoint != null) {
                mWifiManager.save(config, mSaveListener);
            }
        } else {
            if (configController.isEdit()) {//添加网络
              mWifiManager.save(config, mSaveListener);
            } else {
                mWifiManager.connect(config, mConnectListener);
            }
        }
。。。。。
}

4,点击未连接需要输入密码而且未保存的WiFi

当需要输入密码时会将xml文件中的edittext设置为可见,并添加监听watch

代码语言:javascript
复制
if (mPasswordView == null) {
            mPasswordView = (TextView) mView.findViewById(R.id.password);
            mPasswordView.addTextChangedListener(this);
            ((CheckBox) mView.findViewById(R.id.show_password))
                .setOnCheckedChangeListener(this);

            if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
                mPasswordView.setHint(R.string.wifi_unchanged);
            }
        }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-05-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档