android 4.4 wifi 模块开发总结(电视盒子)

时间:2024-03-15 20:56:29

 

        最近6.0的盒子的应用开发已经告一段落了,接到的新需求就是想办法让公司以前发出去的4.4的盒子也得兼容应用。把应用装到4.4盒子上,发现也就文件读取,网络(有线无线),蓝牙,恢复出厂设置这几个模块不能用了,也就是用到6.0的jar包的都不行了。

        6.0wifi,系统有提供jar包,有 WifiTracker,AccessPoint这两个关键类,具体分析等有机会总结,但4.4是没有WifiTracker,AccessPoint这个类放的路径也不一样,导致系统底层提供jar包开发有点困难。所以应用层模拟一个wifi模块出来。结合了其他人的一些成果,也算鼓捣出来一款

android 4.4 wifi 模块开发总结(电视盒子)

4.4wifi开发的难点:

1.如何判定wifi是否打开

2.在wifi打开后扫描wifi

3.判定wifi扫描成功,或得扫描结果

4.确定wifi的各种状态(保存,连接,密码错误等等)

5.连接wifi(有密码与无密码)

6.忘记wifi

7.如何判定wifi已经连接成功(获得ip,网关,子网掩码)

8.wifi要是重名怎么办也就是(ssid一样)

方案:

1.如何判定wifi是否打开

   //获取wifi是否已打开
    public boolean isOpen() {
        boolean isOpen = mWifiManager.isWifiEnabled();
        Log.e(TAG, "wifi是否已打开:" + isOpen);
        return isOpen;
    }

打开wifi

    //打开与关闭wifi
    public void openWifi(boolean isOpen) {
        mWifiManager.setWifiEnabled(isOpen);
    }

2.在wifi打开后扫描wifi

3.判定wifi扫描成功,或得扫描结果

4.确定wifi的各种状态(保存,连接,密码错误等等)

注册一个广播,可以处理这些问题

 public void registerReceiver() {
        IntentFilter 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("android.net.wifi.CONFIGURED_NETWORKS_CHANGE");
        mFilter.addAction("android.net.wifi.LINK_CONFIGURATION_CHANGED");
        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
        if (mReceiver == null) {
            mReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    //处理4.4的广播
                    handleEvent(intent);
                }
            };
        }
        Log.e(TAG, "==注册wifi广播==");
        context.registerReceiver(mReceiver, mFilter);
    }

//wifi是否打开成功的判定

 if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
            //当WiFi被打开、关闭、正在打开、正在关闭或者位置状态即wifi状态发生改变时系统会自动发送该广播,
            // 该广播会附带有两个值,一个是int型表示改变后的state,
            // 可通过字段EXTRA_WIFI_STATE获取,
            // 还有一个是int型的改变前的state(如果有的话)
            // 可通过字段EXTRA_PREVIOUS_WIFI_STATE获取
            // int before_state = intent.getIntExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, 0);
            int after_state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);
            if (after_state == WifiManager.WIFI_STATE_ENABLED) {
                Log.e(TAG, "wifi当前状态:开启");
                scanWifi();
            } else if (after_state == WifiManager.WIFI_STATE_DISABLED) {
                Log.e(TAG, "wifi当前状态:关闭");
                Log.e(TAG, "正在打开wifi");
                openWifi(true);
            }
        } 

//判定扫描成功,获取扫描结果

else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
            scanCompleted = true;
            //获得扫描结果
            List<ScanResult> scanResults = mWifiManager.getScanResults();
            // 得到配置好的网络连接
            List<WifiConfiguration> configuredNetworks = mWifiManager.getConfiguredNetworks();
            if (configuredNetworks != null && configuredNetworks.size() > 0) {
                Log.e(TAG, "得到配置好的网络连接::" + configuredNetworks.toString());
            } else {
                //没有任何配置好的wifi,处理是清空数据库
                Log.e(TAG, "没有任何配置好的wifi,处理是清空数据库");
                wifiDbManager.clearWifiDb();
            }
            if (scanResults != null) {
                List<ScanResult> scanResultList = sortByLevel(scanResults);
                List<Wifi4_0InfoBean> wifiInfoBeanList = new ArrayList<>();
                for (ScanResult re : scanResultList) {
                    //发现扫描的结果出现SSID=""的情况,暂时不清楚原因,过滤这种情况
                    if (re != null && !TextUtils.isEmpty(re.SSID)) {
                        Log.e(TAG, "扫描得到的wifi结果::" + re.toString());
                        Wifi4_0InfoBean wifiInfoBean = new Wifi4_0InfoBean(re);
                        //判断wifi的加密方式
                        wifiInfoBean.setSecurity(getWifiSecurity(re));
                        //设置wifi的强度
                        wifiInfoBean.setLevel(getSignalLevel(re.level));
                        //设置连接状态
                        String state = wifiDbManager.getWifiStatus(re.SSID, re.BSSID);
                        wifiInfoBean.setWifiStatus(state);
                        if (state.equals(Wifi4_0State.CONNECTED)){
                            if (!hasConectWifi(re.SSID,re.BSSID)){
                                wifiInfoBean.setWifiStatus(Wifi4_0State.STATUS_SAVED);
                            }
                            wifiInfoBeanList.add(0,wifiInfoBean);
                        }else if (!state.equals(Wifi4_0State.STATUS_NONE)){
                            if (wifiInfoBeanList.size()==0){
                                wifiInfoBeanList.add(wifiInfoBean);
                            }else {
                                wifiInfoBeanList.add(1,wifiInfoBean);
                            }
                        }else {
                            wifiInfoBeanList.add(wifiInfoBean);
                        }
                    }
                    //通过wpa/wpa2进行保护:[WPA-PSK-CCMP][WPA2-PSK-CCMP][ESS]
                    //通过WPA2进行保护:[WPA2-PSK-CCMP][ESS]
                    //通过wpa/wpa2进行保护(可使用WPS)[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS]
                    //获得接入点的数据:
                }
                Log.e(TAG, "扫描wifi结束:根据强度排序得到wifi的条目" + wifiInfoBeanList.toString());
                if (callback != null) {
                    callback.getWifiList(wifiInfoBeanList);
                }
            }
        }

wifi的状态,因为6.0存在一个accesspoint这个类,这个类封装了wifi的状态,但现在是4.0,4.0底层也有这个类,但一系统层我拿不到,而好像也没封装。所以我就拿了net里的一些状态和自己模拟了一些状态。

package com.ishuidi.boxproject.module.more.network.bean;

/**
 * @创建人:hcy
 * @创建时间:2018/10/29
 * @作用描述:Function
 **/
//wifi4_0状态
public interface Wifi4_0State {
    //准备开始数据连接设置
    static  final  String  IDLE="IDLE";
    //扫描中
    static  final  String  SCANNING="SCANNING";
    //正在连接中
    static  final  String  CONNECTING="CONNECTING";
    //进行身份验证
    static  final  String  AUTHENTICATING="AUTHENTICATING";
    //正在获取Ip地址
    static  final  String  OBTAINING_IPADDR="OBTAINING_IPADDR";
    //已经连接
    static  final  String  CONNECTED="CONNECTED";
    //IP通信暂停
    static  final  String  SUSPENDED="SUSPENDED";
    //当前正在断开数据连接
    static  final  String  DISCONNECTING="DISCONNECTING";
    //已断开
    static  final  String  DISCONNECTED="DISCONNECTED";

    //连接失败
    static  final  String  FAILED="FAILED";
    //对这个网络的访问被阻塞
    static  final  String  BLOCKED="BLOCKED";
    //链接的连通性很差
    static  final  String  VERIFYING_POOR_LINK="VERIFYING_POOR_LINK";
    //检查网络是否为专用门户
    static  final  String  CAPTIVE_PORTAL_CHECK="CAPTIVE_PORTAL_CHECK";

    //无状态
    static  final  String  STATUS_NONE="STATUS_NONE";
    //身份验证出现问题
    static  final  String  STATUS_PASSWORD_ERROR="STATUS_PASSWORD_ERROR";

    //已保存
    static  final  String  STATUS_SAVED="STATUS_SAVED";

    //未启用
    static  final  String STATUS_WIFI_UNABLE="STATUS_WIFI_UNABLE";

}

最后四种状态是我模拟的。

如何判定状态:1.一个大前提需要知道:当4.4盒子同时连接有线和wifi的时候,系统默认用有线,wifi是不启用的,及时输了密码

                            2.状态的保存:我是采取数据库保存wifi的状态的

wifi状态的判定除了输错密码,是通过这个广播判定的:

if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
            //判断wifi是否连接上
            NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
            if (null != info) {
                NetworkInfo.DetailedState state = info.getDetailedState();
                String ssid = mWifiManager.getConnectionInfo().getSSID().replaceAll("\"", "");
                String bssid = mWifiManager.getConnectionInfo().getBSSID();
                Toast.makeText(context, "wifi状态变化: " + state.name() + "???" + ssid + "???" + bssid, Toast.LENGTH_LONG).show();
                Log.d(TAG, "wifi状态变化: " + state.name() + "???" + ssid + "???" + bssid);
                /**
                 * 4.4如果wifi和有线同时连的话,那么连接wifi会一直卡在CAPTIVE_PORTAL_CHECK,应为安卓系统会选择有线网络
                 * 如果断掉有线
                 */
                if (state.name().equals(Wifi4_0State.CAPTIVE_PORTAL_CHECK)) {
                    //4.4连上还是连不上都会经过这里,当有线和无线同时存在的时候会卡死在这个状态
                    //https://blog.csdn.net/yoyo460212643/article/details/78021310
                    //这里处理的是:判断ip地址存不存在
                    updateDb(ssid, Wifi4_0State.CAPTIVE_PORTAL_CHECK, bssid);
                } else if (state.name().equals(Wifi4_0State.CONNECTED)) {
                    //连上了wifi
                    updateDb(ssid, Wifi4_0State.CONNECTED, bssid);
                } else {
                    updateDb(ssid, state.name(), bssid);
                }
            }
            /**
             * IDLE:空闲
             * SCANNING:正在扫描
             * CONNECTING:连接中
             * AUTHENTICATING:正在进行身份验证...
             * OBTAINING_IPADDR:正在获取Ip地址
             * CONNECTED:已连接
             * SUSPENDED:已暂停
             * DISCONNECTING:正在断开连接...
             * DISCONNECTED:已断开
             * FAILED:失败
             * BLOCKED:已阻止
             * VERIFYING_POOR_LINK:暂时关闭(网络状况不佳)
             */
        } 

如何判定已经保存的状态:在获取扫描结果的时候,我采取获取List<ScanResult>和List<WifiConfiguration>,一个是扫描的集合,一个是配置集合,配置的集合指之前连接过的wifi(无论连上还是没有连上),所以可以在扫描结果中根据配置结果,判定含有配置结果的扫描的网络是否连上,连上就给连上状态,没连上就给保存状态。如何判定是否连上wifi:我是通过看此时能否拿到ip地址:

//判断某个wifi是否已经连上
    public boolean hasConectWifi(String ssid, String bssid) {
        ConnectWifiInfo wifiInfo = getConnectWifiINFo();
        boolean flag = false;

        if (wifiInfo != null) {
            String ipAddress = wifiInfo.getTheIPaddress();
            Log.i("WifINfo::", wifiInfo.toString() + "???" + ssid + "???" + bssid + "???" + ipAddress);
            if (!ipAddress.equals("0.0.0.0")) {
                flag = true;
            } else {
                flag = false;
            }
        } else {
            flag = false;
        }

        if (flag) {
            Log.e(TAG, "wifi状态监测::" + ssid + "已经连上了");
            if (callback != null) {
                if (!ssid.equals("0x")) {
                    callback.updateWifiState(ssid, Wifi4_0State.CONNECTED, bssid);
                }
            }
        } else {
            //暂定给一个已保存状态
            updateDb(ssid, Wifi4_0State.STATUS_SAVED, bssid);
        }
        return flag;
    }

5.连接wifi(有密码与无密码),抄的网上的:

 /**
     * 连接wifi
     */
    public void connectWifiWithPwd(String SSID, String Password, WifiCipherType Type, String BSSID) {
        //显示连接中的状态

        //模拟一个正在连接的状态
        updateDb(SSID, Wifi4_0State.CONNECTING, BSSID);
       //callback.updateWifiState(SSID, Wifi4_0State.CONNECTING, BSSID);
        WifiConfiguration tempConfig = this.isExsits(SSID, BSSID);
        if (tempConfig != null) {
            Log.e(TAG, "之前连接过" + SSID + ",重新连接" + BSSID);
            if (!TextUtils.isEmpty(Password)){
                //密码错误重新连接
                tempConfig.preSharedKey = "\"" + Password + "\"";
            }
            connect(tempConfig);
        } else {
            Log.e(TAG, "重来没连接过" + SSID + "");
            WifiConfiguration wifiConfig = createWifiInfo(SSID, Password, Type, BSSID);
            if (wifiConfig != null) {
                connect(wifiConfig);
            }
        }

    }
 private void connect(WifiConfiguration config) {
        // updateDb(config.SSID, Wifi4_0State.CONNECTING, config.BSSID);
        int wcgID = mWifiManager.addNetwork(config);
        boolean b = mWifiManager.enableNetwork(wcgID, true);
        Log.e(TAG, "wifi重连状态监测:配置信息::" + b + "??" + config);
    }

//获取wifi类型,只要根据扫描结果的一个属性

 //判断wifi的安全性:获得扫描后wifi的安全性
    public int getWifiSecurity(ScanResult scanResult) {
        //通过wpa/wpa2进行保护:[WPA-PSK-CCMP][WPA2-PSK-CCMP][ESS]
        //通过WPA2进行保护:[WPA2-PSK-CCMP][ESS]
        //通过wpa/wpa2进行保护(可使用WPS)[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS]
        //获得接入点的数据:
        String capabilities = scanResult.capabilities;
        if (capabilities.contains("WEP")) {
            return SECURITY_WEP;
        } else if (capabilities.contains("PSK")) {
            return SECURITY_PSK;
        } else if (capabilities.contains("EAP")) {
            return SECURITY_EAP;
        }
        return SECURITY_NONE;
    }
 /**
     * 连接wifi需要先形成配置信息
     *
     * @param SSID
     * @param Password
     * @param Type
     * @return
     */
    private WifiConfiguration createWifiInfo(String SSID, String Password,
                                             WifiCipherType Type, String BSSID) {
        WifiConfiguration config = new WifiConfiguration();
        config.allowedAuthAlgorithms.clear();
        config.allowedGroupCiphers.clear();
        config.allowedKeyManagement.clear();
        config.allowedPairwiseCiphers.clear();
        config.allowedProtocols.clear();
        config.SSID = "\"" + SSID + "\"";
        if (!TextUtils.isEmpty(BSSID)){
            config.BSSID = BSSID;
        }
        if (Type == WifiCipherType.WIFICIPHER_NOPASS) {
            //无密码连接wifi一直卡在连接中的状态
            // https://blog.csdn.net/akebrt/article/details/80584965
            // config.wepKeys[0] = "";
            // config.wepTxKeyIndex = 0;
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);

        }
        if (Type == WifiCipherType.WIFICIPHER_WEP) {
            config.preSharedKey = "\"" + Password + "\"";
            config.hiddenSSID = true;
            config.allowedAuthAlgorithms
                    .set(WifiConfiguration.AuthAlgorithm.SHARED);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
            config.allowedGroupCiphers
                    .set(WifiConfiguration.GroupCipher.WEP104);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            config.wepTxKeyIndex = 0;
        }
        if (Type == WifiCipherType.WIFICIPHER_WPA) {
            // 修改之后配置
            config.preSharedKey = "\"" + Password + "\"";
            config.hiddenSSID = true;
            config.allowedAuthAlgorithms
                    .set(WifiConfiguration.AuthAlgorithm.OPEN);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
            config.allowedPairwiseCiphers
                    .set(WifiConfiguration.PairwiseCipher.TKIP);
            // config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.allowedPairwiseCiphers
                    .set(WifiConfiguration.PairwiseCipher.CCMP);
        }

        Log.e(TAG, "createWifiInfo: " + config.toString());
        return config;
    }

6.忘记wifi

//忽略掉指定的wifi
    public void ignoreSomeoneWifi(String SSID, String BSSID) {
        WifiConfiguration tempConfig = this.isExsits(SSID, BSSID);
        if (tempConfig != null) {
            mWifiManager.removeNetwork(tempConfig.networkId);
            mWifiManager.saveConfiguration();
            //mWifiManager.disableNetwork(tempConfig.networkId);
           // mWifiManager.disconnect();
            Toast.makeText(context,"忽略wifi:::成功 " + SSID + "???" + BSSID,Toast.LENGTH_LONG).show();
            Log.e(TAG, "忽略wifi:::成功 " + SSID + "???" + BSSID);
            //显示忘记保存的状态
            updateDb(SSID, Wifi4_0State.STATUS_NONE, BSSID);
            scanWifi();//在扫描一次
        } else {
            Log.e(TAG, "忽略wifi:::错误 " + SSID + "???" + BSSID);
        }


        //int netId = getNetworkId();

    }

7.如何判定wifi已经连接成功(获得ip,网关,子网掩码)

//获取链接的wifi详细信息
    public ConnectWifiInfo getConnectWifiINFo() {
        //mConnectivityManager.
        ConnectWifiInfo connectWifiInfo = new ConnectWifiInfo();
        DhcpInfo dhcpInfo = mWifiManager.getDhcpInfo();

        connectWifiInfo.setTheIPaddress(ipIntToString(dhcpInfo.ipAddress));
        connectWifiInfo.setSubnetMask(ipIntToString(dhcpInfo.netmask));
        connectWifiInfo.setDNSServer(ipIntToString(dhcpInfo.dns1));
        connectWifiInfo.setTheDefaultGateway(ipIntToString(dhcpInfo.gateway));
        return connectWifiInfo;
    }
  /**
     * Function: 将int类型的IP转换成字符串形式的IP<br>
     *
     * @param ip
     * @author ZYT DateTime 2014-5-14 下午12:28:16<br>
     * @return<br>
     */
    public String ipIntToString(int ip) {
        try {
            byte[] bytes = new byte[4];
            bytes[0] = (byte) (0xff & ip);
            bytes[1] = (byte) ((0xff00 & ip) >> 8);
            bytes[2] = (byte) ((0xff0000 & ip) >> 16);
            bytes[3] = (byte) ((0xff000000 & ip) >> 24);
            return Inet4Address.getByAddress(bytes).getHostAddress();
        } catch (Exception e) {
            return "";
        }
    }

8.wifi要是重名怎么办也就是(ssid一样)

6.0wifi判定重名有系统提供的方法,但现在4.0因为某些原因,没有系统的jar包,so,一切从简,我发现ssid一样但bssid不一样。so。

android 4.4 wifi 模块开发总结(电视盒子)

我的思路是判定ssid 和bssid,但貌似还是有些问题

 

反思:模块缺陷:

1.判定重名的方法不对:bssid相当于mac地址,有些路由器可以设置两个同名(ssid一样)的wifi

2.系统会对此刷新wifi的扫描结果,so,对wifi排序的算法不够好(不好就不展示了)

3.概率性存在扫描卡住的情况。需要关闭,再打开,再扫描,原因正在追踪(妥协:15秒内没结果就重启wifi再扫描,也不展示了)

4.判定是否连接上wifi的方法不够好

5.其他基本达到要求:

 

附件:

package com.ishuidi.boxproject.module.more.network.model;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.ishuidi.boxproject.module.more.network.bean.ConnectWifiInfo;
import com.ishuidi.boxproject.module.more.network.bean.Wifi4_0InfoBean;
import com.ishuidi.boxproject.module.more.network.bean.Wifi4_0State;
import com.ishuidi.boxproject.module.more.network.db.DbManager;

import java.net.Inet4Address;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;

/**
 * @创建人:hcy
 * @创建时间:2018/10/24
 * @作用描述:Function 1.当wifi重名的时候也就是SSID是相同的,BSSID是不同的
 **/
public class Wifi4_0Helper {
    private static final String TAG = "==wifi_test==";
    private Context context;
    private WifiManager mWifiManager;
    private ConnectivityManager mConnectivityManager;
    private DbManager wifiDbManager;


    public Wifi4_0Helper(Context context, Wifi4_0CallBack callback) {
        this.context = context;
        this.callback = callback;
        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        mConnectivityManager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        wifiDbManager = DbManager.getInstance();
    }

    public void unregisterReceiver() {
        if (mReceiver != null && context != null) {
            context.unregisterReceiver(mReceiver);
            Log.e(TAG, "==取消wifi广播==");
        }
    }

    //4.0wifi的广播
    private BroadcastReceiver mReceiver;

    public void registerReceiver() {
        IntentFilter 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("android.net.wifi.CONFIGURED_NETWORKS_CHANGE");
        mFilter.addAction("android.net.wifi.LINK_CONFIGURATION_CHANGED");
        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
        if (mReceiver == null) {
            mReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    //处理4.4的广播
                    handleEvent(intent);
                }
            };
        }
        Log.e(TAG, "==注册wifi广播==");
        context.registerReceiver(mReceiver, mFilter);
    }


    //是否支持wifi直连
    public boolean isMP2pSupported() {
        boolean mP2pSupported = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT);
        Log.e(TAG, "wifi是否支持直连:" + mP2pSupported);
        return mP2pSupported;
    }

    //获取wifi是否已打开
    public boolean isOpen() {
        boolean isOpen = mWifiManager.isWifiEnabled();
        Log.e(TAG, "wifi是否已打开:" + isOpen);
        return isOpen;
    }

    //打开与关闭wifi
    public void openWifi(boolean isOpen) {
        mWifiManager.setWifiEnabled(isOpen);
    }

    static final int SECURITY_NONE = 0;
    static final int SECURITY_WEP = 1;
    static final int SECURITY_PSK = 2;
    static final int SECURITY_EAP = 3;

    //判断wifi的安全性:获得扫描后wifi的安全性
    public int getWifiSecurity(ScanResult scanResult) {
        //通过wpa/wpa2进行保护:[WPA-PSK-CCMP][WPA2-PSK-CCMP][ESS]
        //通过WPA2进行保护:[WPA2-PSK-CCMP][ESS]
        //通过wpa/wpa2进行保护(可使用WPS)[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS]
        //获得接入点的数据:
        String capabilities = scanResult.capabilities;
        if (capabilities.contains("WEP")) {
            return SECURITY_WEP;
        } else if (capabilities.contains("PSK")) {
            return SECURITY_PSK;
        } else if (capabilities.contains("EAP")) {
            return SECURITY_EAP;
        }
        return SECURITY_NONE;
    }


    //倒计时
    public static Flowable<Integer> countDownTime(int time) {
        if (time < 0) {
            time = 0;
        }
        final int countTime = time;
        return Flowable.interval(0, 1, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .map((increaseTime) -> {
                    //解决八小时的时区问题
                    return countTime - increaseTime.intValue();
                }).take(countTime + 1);

    }

    private Disposable timeSubscribe;

    private void countTimeForScanWifi() {
        if (timeSubscribe != null) {
            timeSubscribe.dispose();
        }
        timeSubscribe = countDownTime(15).subscribe((time) -> {
            if (time > 0) {

            } else if (time == 0) {
                if (!scanCompleted) {
                    //重启wifi
                    Log.e(TAG, "15秒内没有得到扫描数据: " + "重启wifi");
                    Log.e(TAG, "正在关闭wifi");
                    openWifi(false);
                    if (timeSubscribe != null) {
                        timeSubscribe.dispose();
                    }
                }
            }
        });
    }


    private void updateDb(String ssid, String wifi_state, String bssid) {
        //插入wifi状态记录

        if (ssid.equals("0x") || ssid.equals("<unknown ssid>") && bssid == null) {

        } else {
            Log.e(TAG, "wifi状态监测::" + wifi_state + "??" + ssid + "???" + bssid);
            wifiDbManager.insertOrUpdateWifi(ssid, wifi_state, bssid);
            if (callback != null) {
                if (!ssid.equals("0x")) {
                    callback.updateWifiState(ssid, wifi_state, bssid);
                }
            }
        }

    }

    public void handleEvent(Intent intent) {
        String action = intent.getAction();
        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
            //当WiFi被打开、关闭、正在打开、正在关闭或者位置状态即wifi状态发生改变时系统会自动发送该广播,
            // 该广播会附带有两个值,一个是int型表示改变后的state,
            // 可通过字段EXTRA_WIFI_STATE获取,
            // 还有一个是int型的改变前的state(如果有的话)
            // 可通过字段EXTRA_PREVIOUS_WIFI_STATE获取
            // int before_state = intent.getIntExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, 0);
            int after_state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);
            if (after_state == WifiManager.WIFI_STATE_ENABLED) {
                Log.e(TAG, "wifi当前状态:开启");
                scanWifi();
            } else if (after_state == WifiManager.WIFI_STATE_DISABLED) {
                Log.e(TAG, "wifi当前状态:关闭");
                Log.e(TAG, "正在打开wifi");
                openWifi(true);
            }
        } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
            scanCompleted = true;
            //获得扫描结果
            List<ScanResult> scanResults = mWifiManager.getScanResults();
            // 得到配置好的网络连接
            List<WifiConfiguration> configuredNetworks = mWifiManager.getConfiguredNetworks();
            if (configuredNetworks != null && configuredNetworks.size() > 0) {
                Log.e(TAG, "得到配置好的网络连接::" + configuredNetworks.toString());
            } else {
                //没有任何配置好的wifi,处理是清空数据库
                Log.e(TAG, "没有任何配置好的wifi,处理是清空数据库");
                wifiDbManager.clearWifiDb();
            }
            if (scanResults != null) {
                List<ScanResult> scanResultList = sortByLevel(scanResults);
                List<Wifi4_0InfoBean> wifiInfoBeanList = new ArrayList<>();
                for (ScanResult re : scanResultList) {
                    //发现扫描的结果出现SSID=""的情况,暂时不清楚原因,过滤这种情况
                    if (re != null && !TextUtils.isEmpty(re.SSID)) {
                        Log.e(TAG, "扫描得到的wifi结果::" + re.toString());
                        Wifi4_0InfoBean wifiInfoBean = new Wifi4_0InfoBean(re);
                        //判断wifi的加密方式
                        wifiInfoBean.setSecurity(getWifiSecurity(re));
                        //设置wifi的强度
                        wifiInfoBean.setLevel(getSignalLevel(re.level));
                        //设置连接状态
                        String state = wifiDbManager.getWifiStatus(re.SSID, re.BSSID);
                        wifiInfoBean.setWifiStatus(state);
                        if (state.equals(Wifi4_0State.CONNECTED)){
                            if (!hasConectWifi(re.SSID,re.BSSID)){
                                wifiInfoBean.setWifiStatus(Wifi4_0State.STATUS_SAVED);
                            }
                            wifiInfoBeanList.add(0,wifiInfoBean);
                        }else if (!state.equals(Wifi4_0State.STATUS_NONE)){
                            if (wifiInfoBeanList.size()==0){
                                wifiInfoBeanList.add(wifiInfoBean);
                            }else {
                                wifiInfoBeanList.add(1,wifiInfoBean);
                            }
                        }else {
                            wifiInfoBeanList.add(wifiInfoBean);
                        }
                    }
                    //通过wpa/wpa2进行保护:[WPA-PSK-CCMP][WPA2-PSK-CCMP][ESS]
                    //通过WPA2进行保护:[WPA2-PSK-CCMP][ESS]
                    //通过wpa/wpa2进行保护(可使用WPS)[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS]
                    //获得接入点的数据:
                }
                Log.e(TAG, "扫描wifi结束:根据强度排序得到wifi的条目" + wifiInfoBeanList.toString());
                if (callback != null) {
                    callback.getWifiList(wifiInfoBeanList);
                }
            }
        } /*else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) ||
                WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {

        }*/ else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
            int error = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0);
            int err2 = intent.getIntExtra(WifiManager.EXTRA_NEW_STATE, 0);
            Log.d(TAG, "wifi错误分析::" + error + "???" + err2);

            if (WifiManager.ERROR_AUTHENTICATING == error) {
                //密码错误,认证失败
                String ssid = mWifiManager.getConnectionInfo().getSSID().replaceAll("\"", "");
                String bssid = mWifiManager.getConnectionInfo().getBSSID();
                Log.e(TAG, "wifi状态监测::身份验证失败(密码错误)" + ssid);
                updateDb(ssid, Wifi4_0State.STATUS_PASSWORD_ERROR, bssid);

            }
        } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
            //判断wifi是否连接上
            NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
            if (null != info) {
                NetworkInfo.DetailedState state = info.getDetailedState();
                String ssid = mWifiManager.getConnectionInfo().getSSID().replaceAll("\"", "");
                String bssid = mWifiManager.getConnectionInfo().getBSSID();
                Toast.makeText(context, "wifi状态变化: " + state.name() + "???" + ssid + "???" + bssid, Toast.LENGTH_LONG).show();
                Log.d(TAG, "wifi状态变化: " + state.name() + "???" + ssid + "???" + bssid);
                /**
                 * 4.4如果wifi和有线同时连的话,那么连接wifi会一直卡在CAPTIVE_PORTAL_CHECK,应为安卓系统会选择有线网络
                 * 如果断掉有线
                 */
                if (state.name().equals(Wifi4_0State.CAPTIVE_PORTAL_CHECK)) {
                    //4.4连上还是连不上都会经过这里,当有线和无线同时存在的时候会卡死在这个状态
                    //https://blog.csdn.net/yoyo460212643/article/details/78021310
                    //这里处理的是:判断ip地址存不存在
                    updateDb(ssid, Wifi4_0State.CAPTIVE_PORTAL_CHECK, bssid);
                } else if (state.name().equals(Wifi4_0State.CONNECTED)) {
                    //连上了wifi
                    updateDb(ssid, Wifi4_0State.CONNECTED, bssid);
                } else {
                    updateDb(ssid, state.name(), bssid);
                }
            }
            /**
             * IDLE:空闲
             * SCANNING:正在扫描
             * CONNECTING:连接中
             * AUTHENTICATING:正在进行身份验证...
             * OBTAINING_IPADDR:正在获取Ip地址
             * CONNECTED:已连接
             * SUSPENDED:已暂停
             * DISCONNECTING:正在断开连接...
             * DISCONNECTED:已断开
             * FAILED:失败
             * BLOCKED:已阻止
             * VERIFYING_POOR_LINK:暂时关闭(网络状况不佳)
             */
        } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
            //强度变化的广播
        }
    }

    private boolean scanCompleted = false;

    /**
     * 扫描
     */
    private void scanWifi() {
        Log.e(TAG, "开始扫描wifi");
        scanCompleted = false;
        mWifiManager.startScan();
        countTimeForScanWifi();
    }

    /**
     * 将扫描到的wifi的结果根据强度由高到低排序
     *
     * @param list
     * @return
     */
    private List<ScanResult> sortByLevel(List<ScanResult> list) {
        Collections.sort(list, new Comparator<ScanResult>() {
            @Override
            public int compare(ScanResult scanResult, ScanResult t1) {
                int i = mWifiManager.calculateSignalLevel(t1.level, 4) - mWifiManager.calculateSignalLevel(scanResult.level, 4);
                return i;
            }
        });
        return list;
    }


    /**
     * 根据ScanResult.level 算出三个级别的信号强度
     *
     * @param level
     * @return
     */
    public int getSignalLevel(int level) {
        if (Math.abs(level) >= 70) {
            return 1;
        } else if (Math.abs(level) >= 60) {
            return 2;
        } else {
            return 3;
        }
    }


    private Wifi4_0CallBack callback;

    // 查看以前是否也配置过这个网络
    //
    public WifiConfiguration isExsits(String SSID, String BSSID) {
        List<WifiConfiguration> existingConfigs = mWifiManager
                .getConfiguredNetworks();
        Log.e(TAG, "2222===" + SSID + "???" + BSSID);
        List<WifiConfiguration> list=new ArrayList<WifiConfiguration>();
        if (existingConfigs != null) {
            for (WifiConfiguration existingConfig : existingConfigs) {
                Log.e(TAG, "1111===" + existingConfig.SSID + "???" + existingConfig.BSSID);
                if (BSSID == null) {
                    if (existingConfig != null && existingConfig.SSID.equals("\"" + SSID + "\"")) {
                        return existingConfig;
                    }
                } else {
                    if (existingConfig != null && existingConfig.SSID.equals("\"" + SSID + "\"") &&
                            existingConfig.BSSID != null && existingConfig.BSSID.equals(BSSID)) {
                        return existingConfig;
                    }else {
                        if (existingConfig!=null&&existingConfig.SSID.equals("\"" + SSID + "\"")){
                            list.add(existingConfig);
                        }
                    }
                }
            }
        }
        if (list.size()==1){
            return list.get(0);
        }
        return null;
    }

    private void connect(WifiConfiguration config) {
        // updateDb(config.SSID, Wifi4_0State.CONNECTING, config.BSSID);
        int wcgID = mWifiManager.addNetwork(config);
        boolean b = mWifiManager.enableNetwork(wcgID, true);
        Log.e(TAG, "wifi重连状态监测:配置信息::" + b + "??" + config);
    }


    /**
     * 连接wifi
     */
    public void connectWifiWithPwd(String SSID, String Password, WifiCipherType Type, String BSSID) {
        //显示连接中的状态

        //模拟一个正在连接的状态
        updateDb(SSID, Wifi4_0State.CONNECTING, BSSID);
       //callback.updateWifiState(SSID, Wifi4_0State.CONNECTING, BSSID);
        WifiConfiguration tempConfig = this.isExsits(SSID, BSSID);
        if (tempConfig != null) {
            Log.e(TAG, "之前连接过" + SSID + ",重新连接" + BSSID);
            if (!TextUtils.isEmpty(Password)){
                //密码错误重新连接
                tempConfig.preSharedKey = "\"" + Password + "\"";
            }
            connect(tempConfig);
        } else {
            Log.e(TAG, "重来没连接过" + SSID + "");
            WifiConfiguration wifiConfig = createWifiInfo(SSID, Password, Type, BSSID);
            if (wifiConfig != null) {
                connect(wifiConfig);
            }
        }

    }



    public void connectAddWifi(String SSID, String Password, WifiCipherType Type){
        WifiConfiguration wifiConfig = createWifiInfo(SSID, Password, Type,"");
        if (wifiConfig != null) {
            Log.e(TAG, "connectAddWifi: "+wifiConfig.toString());
            connect(wifiConfig);
        }
    }


    /**
     * 连接wifi需要先形成配置信息
     *
     * @param SSID
     * @param Password
     * @param Type
     * @return
     */
    private WifiConfiguration createWifiInfo(String SSID, String Password,
                                             WifiCipherType Type, String BSSID) {
        WifiConfiguration config = new WifiConfiguration();
        config.allowedAuthAlgorithms.clear();
        config.allowedGroupCiphers.clear();
        config.allowedKeyManagement.clear();
        config.allowedPairwiseCiphers.clear();
        config.allowedProtocols.clear();
        config.SSID = "\"" + SSID + "\"";
        if (!TextUtils.isEmpty(BSSID)){
            config.BSSID = BSSID;
        }
        if (Type == WifiCipherType.WIFICIPHER_NOPASS) {
            //无密码连接wifi一直卡在连接中的状态
            // https://blog.csdn.net/akebrt/article/details/80584965
            // config.wepKeys[0] = "";
            // config.wepTxKeyIndex = 0;
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);

        }
        if (Type == WifiCipherType.WIFICIPHER_WEP) {
            config.preSharedKey = "\"" + Password + "\"";
            config.hiddenSSID = true;
            config.allowedAuthAlgorithms
                    .set(WifiConfiguration.AuthAlgorithm.SHARED);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
            config.allowedGroupCiphers
                    .set(WifiConfiguration.GroupCipher.WEP104);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            config.wepTxKeyIndex = 0;
        }
        if (Type == WifiCipherType.WIFICIPHER_WPA) {
            // 修改之后配置
            config.preSharedKey = "\"" + Password + "\"";
            config.hiddenSSID = true;
            config.allowedAuthAlgorithms
                    .set(WifiConfiguration.AuthAlgorithm.OPEN);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
            config.allowedPairwiseCiphers
                    .set(WifiConfiguration.PairwiseCipher.TKIP);
            // config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.allowedPairwiseCiphers
                    .set(WifiConfiguration.PairwiseCipher.CCMP);
        }

        Log.e(TAG, "createWifiInfo: " + config.toString());
        return config;
    }


    public interface Wifi4_0CallBack {
        void getWifiList(List<Wifi4_0InfoBean> wifiInfoBeanList);

        void updateWifiState(String ssid, String name, String BSSID);
    }

    // 定义几种加密方式,一种是WEP,一种是WPA,还有没有密码的情况
    public enum WifiCipherType {
        WIFICIPHER_WEP, WIFICIPHER_WPA, WIFICIPHER_NOPASS, WIFICIPHER_INVALID
    }


    //获取链接的wifi详细信息
    public ConnectWifiInfo getConnectWifiINFo() {
        //mConnectivityManager.
        ConnectWifiInfo connectWifiInfo = new ConnectWifiInfo();
        DhcpInfo dhcpInfo = mWifiManager.getDhcpInfo();

        connectWifiInfo.setTheIPaddress(ipIntToString(dhcpInfo.ipAddress));
        connectWifiInfo.setSubnetMask(ipIntToString(dhcpInfo.netmask));
        connectWifiInfo.setDNSServer(ipIntToString(dhcpInfo.dns1));
        connectWifiInfo.setTheDefaultGateway(ipIntToString(dhcpInfo.gateway));
        return connectWifiInfo;
    }

    /**
     * Function: 将int类型的IP转换成字符串形式的IP<br>
     *
     * @param ip
     * @author ZYT DateTime 2014-5-14 下午12:28:16<br>
     * @return<br>
     */
    public String ipIntToString(int ip) {
        try {
            byte[] bytes = new byte[4];
            bytes[0] = (byte) (0xff & ip);
            bytes[1] = (byte) ((0xff00 & ip) >> 8);
            bytes[2] = (byte) ((0xff0000 & ip) >> 16);
            bytes[3] = (byte) ((0xff000000 & ip) >> 24);
            return Inet4Address.getByAddress(bytes).getHostAddress();
        } catch (Exception e) {
            return "";
        }
    }


    //忽略掉指定的wifi
    public void ignoreSomeoneWifi(String SSID, String BSSID) {
        WifiConfiguration tempConfig = this.isExsits(SSID, BSSID);
        if (tempConfig != null) {
            mWifiManager.removeNetwork(tempConfig.networkId);
            mWifiManager.saveConfiguration();
            //mWifiManager.disableNetwork(tempConfig.networkId);
           // mWifiManager.disconnect();
            Toast.makeText(context,"忽略wifi:::成功 " + SSID + "???" + BSSID,Toast.LENGTH_LONG).show();
            Log.e(TAG, "忽略wifi:::成功 " + SSID + "???" + BSSID);
            //显示忘记保存的状态
            updateDb(SSID, Wifi4_0State.STATUS_NONE, BSSID);
            scanWifi();//在扫描一次
        } else {
            Log.e(TAG, "忽略wifi:::错误 " + SSID + "???" + BSSID);
        }


        //int netId = getNetworkId();

    }

    /*   public void forgetWifi() {
           int networkId = mWifiManager.getConnectionInfo().getNetworkId();
           mWifiManager.disableNetwork(networkId);
           mWifiManager.disconnect();
           Log.d(TAG, "systemForget:--> systemForget: " + networkId);
       }*/
    //判断某个wifi是否已经连上
    public boolean hasConectWifi(String ssid, String bssid) {
        ConnectWifiInfo wifiInfo = getConnectWifiINFo();
        boolean flag = false;

        if (wifiInfo != null) {
            String ipAddress = wifiInfo.getTheIPaddress();
            Log.i("WifINfo::", wifiInfo.toString() + "???" + ssid + "???" + bssid + "???" + ipAddress);
            if (!ipAddress.equals("0.0.0.0")) {
                flag = true;
            } else {
                flag = false;
            }
        } else {
            flag = false;
        }

        if (flag) {
            Log.e(TAG, "wifi状态监测::" + ssid + "已经连上了");
            if (callback != null) {
                if (!ssid.equals("0x")) {
                    callback.updateWifiState(ssid, Wifi4_0State.CONNECTED, bssid);
                }
            }
        } else {
            //暂定给一个已保存状态
            updateDb(ssid, Wifi4_0State.STATUS_SAVED, bssid);
        }
        return flag;
    }


    //保存状态下的链接
    public void connectHasSavedWifi(String SSID, String BSSID) {
        WifiConfiguration tempConfig = this.isExsits(SSID, BSSID);
        if (tempConfig != null) {
            Log.e(TAG, "之前连接过>>>" + SSID + ",重新连接");
            //模拟个正在连接的状态
            updateDb(SSID, Wifi4_0State.CONNECTING, BSSID);
           // callback.updateWifiState(SSID, Wifi4_0State.CONNECTING, BSSID);
            connect(tempConfig);
        } else {
            Log.e(TAG, "之前没连接过>>>" + SSID + ",重新连接");
            callback.updateWifiState(SSID, Wifi4_0State.STATUS_NONE, BSSID);
        }
    }


    public boolean wifiHasConnected(String ssid, String bssid) {
        WifiInfo mWifiManagerConnectionInfo = mWifiManager.getConnectionInfo();
        if (mWifiManagerConnectionInfo.getSupplicantState() == SupplicantState.COMPLETED) {
            if (mWifiManagerConnectionInfo.getSSID().replaceAll("\"", "").equals(ssid) &&
                    mWifiManagerConnectionInfo.getBSSID().equals(bssid)) {
                return true;
            }
        }
        return false;
    }
}