前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android开发笔记(六十)网络的检测与连接

Android开发笔记(六十)网络的检测与连接

作者头像
aqi00
发布2019-01-18 11:08:55
3.6K0
发布2019-01-18 11:08:55
举报

检测网络

APP在访问网络之前,正常都要先检测网络状态,因为如果未连接网络就上网的话,常常导致超时等待。另外,APP有时也需区分当前网络是wifi环境还是数据连接环境,如果是数据连接环境,那么为了节省流量,一般不进行下载操作也不加载大图片;如果是wifi环境,那就都可以做而不必担心消耗流量。 ConnectivityManager就是用于检测网络连接的工具类,其对象从系统服务Context.CONNECTIVITY_SERVICE中获取。该类的常用方法是getActiveNetworkInfo,调用该方法返回一个NetworkInfo对象,下面是NetworkInfo的常用方法: getType : 获取网络类型。ConnectivityManager.TYPE_WIFI表示wifi,ConnectivityManager.TYPE_MOBILE表示数据连接,ConnectivityManager.TYPE_WIMAX表示wimax,ConnectivityManager.TYPE_ETHERNET表示以太网,ConnectivityManager.TYPE_BLUETOOTH表示蓝牙。 getState : 获取网络状态。State.CONNECTING表示正在连接,State.CONNECTED表示已连接,State.SUSPENDED表示挂起,State.DISCONNECTING表示正在断开,State.DISCONNECTED表示已断开,State.UNKNOWN表示未知。 getSubtype : 获取网络子类型。当网络类型为数据连接时,子类型为2G/3G/4G的细分类型,如CDMA、EVDO、HSDPA、LTE等等。 当网络类型是wifi时,要想获取详细的wifi信息,又得使用WifiManager,该类的对象从系统服务Context.WIFI_SERVICE中获取。下面是WifiManager的常用网络检测方法: isWifiEnabled : 判断WLAN功能是否开启 setWifiEnabled : 开关WLAN功能 getWifiState : 获取当前wifi的状态。WIFI_STATE_DISABLED表示已断开,WIFI_STATE_DISABLING表示正在断开,WIFI_STATE_ENABLED表示已连上,WIFI_STATE_ENABLING表示正在连接,WIFI_STATE_UNKNOWN表示未知。 getConnectionInfo : 获取当前wifi的连接信息。该方法返回一个WifiInfo对象,WifiInfo可通过相应的get方法获取如下信息:wifi名称、路由器MAC、WIFI信号强度、连接速率、IP地址、MAC地址、网络编号等等。

连接wifi

下面是WifiManager的常用网络检测方法: startScan : 开始扫描周围的wifi信息。 getScanResults : 获取周围wifi的扫描结果。 calculateSignalLevel : 根据信号强度计算信号等级。 getConfiguredNetworks : 获取已配置的网络信息。 addNetwork : 添加指定wifi配置。 enableNetwork : 启用指定wifi。第二个参数表示是否同时禁用其他的wifi disableNetwork : 禁用指定wifi。 disconnect : 断开当前wifi。 要连上某个具体的wifi,实际开发中的调用顺序为:首先调用startScan开始扫描周围wifi,然后调用getScanResults获取扫描的wifi列表,接着通过getConfiguredNetworks查找已配置的网络信息;如果找到指定的网络配置,则调用enableNetwork启用该wifi;如果没找到指定wifi配置,则先调用addNetwork添加wifi配置(addNetwork会返回一个网络ID来标识刚添加的wifi),然后调用enableNetwork启用该wifi。 需要注意的是,在addNetwork之前还得创建新的wifi配置信息,即一个WifiConfiguration实例。WifiConfiguration的赋值比较难懂,就不费口舌了,直接上代码:

	private WifiConfiguration createWifiInfo(String ssid, String password, int type) {
		WifiConfiguration config = new WifiConfiguration();
		config.SSID = "\"" + ssid + "\"";
		if (type == WifiConfiguration.KeyMgmt.NONE) {  //明文密码
			config.wepKeys[0] = "";
			config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
			config.wepTxKeyIndex = 0;
		} else {  //WPA加密或者WPA2加密
			config.preSharedKey = "\"" + password + "\"";
			config.hiddenSSID = true;
			config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
			config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
			config.allowedKeyManagement.set(type);
			config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
			config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
			config.status = WifiConfiguration.Status.ENABLED;
		}
		return config;
	}

若要断开当前的wifi连接,则既可调用disableNetwork方法,也可调用disconnect方法。disconnect与disableNetwork的区别在于:disableNetwork不但断开连接,并且此后也不会自动重连;而disconnect只是断开本次连接,不会阻止将来的自动重连。

反射reflect

Android因为自身在不断更新升级,同时新技术也是层出不穷,所以并没有把所有的公共方法开放出来。如果我们查看Android的sdk源码,会发现少数函数被标记了hide,表示该函数虽然是public但尚未正式开放,可能是不稳定或者有待完善。可是有时我们又确实需要调用这些隐藏方法,就得通过java的反射机制来间接实现。反射机制指的是在运行过程中,程序对于任意一个类,都知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,而不被hide标记所束缚。 关于反射机制的原理说来话长,我们还是直接说说它的实际应用。首先获取目标类的Class对象,可通过调用对象的getClass方法或者调用Class.forName方法;其次调用该Class对象的getMethod方法,这里需要指定将要访问的方法名、方法参数(先传入参数的类型)等等;再次调用Method的invoke方法,即输入Class对象,以及各参数的具体取值;最后获取invoke的返回值,也就是方法调用的返回结果。 下面是实际开发中运用反射的两个代码例子: 1、开关个人热点

      Method method = wifiMgr.getClass().getMethod(
              "setWifiApEnabled", WifiConfiguration.class, Boolean.TYPE);
      Boolean result = (Boolean) method.invoke(wifiMgr, apConfig, true);

2、获取手机序列号

			Class<?> c = Class.forName("android.os.SystemProperties");
			Method get = c.getMethod("get", String.class);
			String serial = (String) get.invoke(c, "ro.serialno");

如果大家留心,可能发现前面的一些博文已经运用了反射机制,具体说明如下: 1、SignalStrength类获取LTE信号的相关方法,如getLteSignalStrength、getLteRsrp、getLteRsrq等等,参见《Android开发笔记(四十六)手机相关事件》 2、TelephonyManager类获取网络大类与名称的相关方法,如getNetworkClass和getNetworkTypeName,参见《Android开发笔记(五十五)手机设备基本操作》 3、ConnectivityManager类数据连接的相关方法,如getMobileDataEnabled和setMobileDataEnabled,参见《Android开发笔记(五十五)手机设备基本操作》 4、WifiManager类管理热点的相关方法,如setWifiApEnabled、getWifiApState、getWifiApConfiguration等等,参见《Android开发笔记(六十)网络的检测与连接》 5、StorageManager类管理存储的相关方法,如getVolumePaths等等,参见《Android开发笔记(七十九)资源与权限校验

个人热点

Android支持把手机变成一个wifi热点,其他手机可接入该手机的wifi,从而共享服务端手机的数据流量。下面是WifiManager中与热点相关的方法(注意这些方法都是隐藏的,得通过反射机制来调用): setWifiApEnabled : 开关热点。true表示开启,false表示关闭。 getWifiApState : WIFI_AP_STATE_DISABLED表示已断开,WIFI_AP_STATE_DISABLING表示正在断开,WIFI_AP_STATE_ENABLED表示已连接,WIFI_AP_STATE_ENABLING表示正在连接,WIFI_AP_STATE_FAILED表示开关失败。 isWifiApEnabled : 判断热点是否启用。只有已连接状态才返回true,其余都返回false。 getWifiApConfiguration : 获取热点的配置信息。 setWifiApConfiguration : 设置热点的配置信息。 因为热点管理本身就不是很完善,所以还存在一些目前无法解决的问题。下面是热点编码的几个注意事项: 1、wifi和热点不能同时打开,所以打开热点的时候需要关闭wifi。 2、热点的配置信息主要有:热点名称、热点密码、加密方式(常用的有明文、WPA、WPA2三种)。如果更改了热点配置,新配置并不会立即生效;只能先关闭热点,然后使用新配置开启热点,新配置才会生效。 3、要想查看连上本机热点的设备,可定期扫描系统文件/proc/net/arp,该文件保存了与本机连接的设备列表。可是这些设备并不一定都真正连上,所以还得检测对方IP是否连通。检测连通性可使用InetAddress的isReachable,不过实际测试发现,部分笔记本电脑已连上,但isReachable结果却是连不上。此时又得调用系统的ping命令,如果ping得通,那么不管isReachable结果为何,都算是已连上。 下面是热点管理的几个尚待解决的问题(至少博主目前没办法,若有朋友解决了还请不吝赐教): 1、/proc/net/arp能找到已连接设备的IP和MAC,却找不到对方设备的真实名称(文件中有名称字段,可是实际测试发现该字段都是ap0或者wlan0这种笼统名称); --目前该问题已解决。 --对于连接热点的手机,可通过该手机的MAC地址查询对应的厂商名称,MAC与厂商的对应关系表在这里:http://standards.ieee.org/regauth/oui/oui.txt(该方法的原理是:联网设备的MAC由国际电子协会IEEE统一分配,未经认证和授权的厂家无权生产,其中MAC地址的前六位就代表手机/电脑的厂商) --对于连接热点的电脑,可使用该电脑的IP通过socket方式经由NETBIOS协议获取电脑的MAC和计算机名,当然前提是对方电脑要正常开启NETBIOS服务(系统服务中的“TCP/IP NetBIOS Helper”),具体代码参见《Android开发笔记(六十九)JNI实战》 2、WifiManager没有阻止某个设备连接热点的方法,其他公开的api也没发现能够实现该功能的方法; --目前该问题尚未解决。(原本以为解决,但无法实现,详情见下) --WifiManager有个隐藏方法addToBlacklist,该方法可以把指定设备添加到黑名单,也就是阻止该设备连接热点。 ----经反复试验,原生的addToBlacklist方法其实并不会生效。部分手机能够支持阻止某台设备,应该是厂商自己修改了Android内核。 3、无法查看每个设备的流量使用情况。linux下有个iftop工具可以统计每个设备的设备流量,Android作为一个瘦身版的linux,虽然也有iftop工具,但是功能简单没法统计单个的流量。 对于以上问题,有的机型可以支持,有的不能支持,不知道支持的机型是不是改写了Android的内核源码。

代码示例

下面是检测网络的代码示例:

import com.example.exmnetwork.util.Utils;
import com.example.exmnetwork.util.IPv4Util;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.telephony.TelephonyManager;
import android.widget.TextView;

public class InfoActivity extends Activity {

	private static final String TAG = "InfoActivity";
	private ConnectivityManager mConnectMgr;
	private TelephonyManager mTelMgr;
	
	private TextView tv_info;
	private TextView tv_all;
	private Handler mHandler = new Handler();
	private String[] mNetStateArray = {"正在连接", "已连接", "暂停", 
			"正在断开", "已断开", "未知"};
	private String[] mWifiStateArray = {"正在断开", "已断开", "正在连接", 
			"已连接", "未知"};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_info);

		tv_info = (TextView) findViewById(R.id.tv_info);
		tv_all = (TextView) findViewById(R.id.tv_all);
		mHandler.postDelayed(mRefresh, 50);;
	}

	private Runnable mRefresh = new Runnable() {
		@Override
		public void run() {
			getAvailableNet();
			getAllNetwork();
			mHandler.postDelayed(this, 1000);;
		}
	};

	@SuppressLint("DefaultLocale")
	private void getAvailableNet() {
		String desc = "";
		mTelMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
		mConnectMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo info = mConnectMgr.getActiveNetworkInfo();
		if (info != null && info.getState() == NetworkInfo.State.CONNECTED) {
			if (info.getType() == ConnectivityManager.TYPE_WIFI) {
				WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
		        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
		        int state = wifiManager.getWifiState();
		        String SSID = wifiInfo.getSSID();
		        if (SSID == null || SSID.length()<=0 || SSID.indexOf("unknown")>=0) {
		        	desc = "\n当前联网的网络类型是WIFI,但未成功连接已知的wifi信号";
		        } else {
		        	desc = String.format("%s当前联网的网络类型是WIFI,", desc);
		        	desc = String.format("%s状态是%s。\n", desc, mWifiStateArray[state]);
		        	desc = String.format("%s WIFI名称是:%s\n", desc, SSID);
		        	desc = String.format("%s 路由器MAC是:%s\n", desc, wifiInfo.getBSSID());
		        	desc = String.format("%s WIFI信号强度是:%s\n", desc, wifiInfo.getRssi());
		        	desc = String.format("%s 连接速率是:%s\n", desc, wifiInfo.getLinkSpeed());
		        	desc = String.format("%s IP地址是:%s\n", desc, IPv4Util.intToIp(wifiInfo.getIpAddress()));
		        	desc = String.format("%s MAC地址是:%s\n", desc, wifiInfo.getMacAddress());
		        	desc = String.format("%s 网络编号是:%s\n", desc, wifiInfo.getNetworkId());
		        }
			} else if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
				int net_type = info.getSubtype();
				desc = String.format("\n当前联网的网络类型是%s %s", Utils.getNetworkTypeName(mTelMgr, net_type), Utils.getClassName(mTelMgr, net_type));
			} else {
				desc = String.format("\n当前联网的网络类型是%d", info.getType());
			}
		} else {
			desc = "\n当前无上网连接";
		}
		tv_info.setText(desc);
	}
	
	private void getAllNetwork() {
		String desc = "";
		NetworkInfo[] info = mConnectMgr.getAllNetworkInfo();
		if (info != null) {
			for (int i = 0; i < info.length; i++) {
				//NetworkInfo.State.CONNECTED 此状态表示已连接
				desc = String.format("%s%s %s %s\n", desc, mNetStateArray[info[i].getState().ordinal()],
						info[i].getTypeName(), info[i].getSubtypeName());
			}
			tv_all.setText(desc);
		}
	}

}

下面是连接wifi的代码示例:

import java.util.ArrayList;
import java.util.List;

import com.example.exmnetwork.adapter.WifiListAdapter;
import com.example.exmnetwork.bean.WifiConnect;
import com.example.exmnetwork.dialog.InputDialogFragment.InputCallbacks;
import com.example.exmnetwork.util.Utils;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

@SuppressLint("DefaultLocale")
public class WifiActivity extends Activity implements OnCheckedChangeListener,InputCallbacks {

	private static final String TAG = "WifiActivity";
	private WifiManager mWifiManager;
	private TextView tv_result;
	private TextView tv_config;
	private ListView lv_wifi;
	private CheckBox ck_wlan;
	private Handler mHandler = new Handler();

	@Override
	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_wifi);

		tv_result = (TextView) findViewById(R.id.tv_result);
		tv_config = (TextView) findViewById(R.id.tv_config);
		lv_wifi = (ListView) findViewById(R.id.lv_wifi);
		ck_wlan = (CheckBox) findViewById(R.id.ck_wlan);
		if (Utils.getWlanStatus(this) == true) {
			ck_wlan.setChecked(true);
		}
		ck_wlan.setOnCheckedChangeListener(this);
		
		mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
		mHandler.postDelayed(mRefresh, 50);;
	}

	@Override
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
		if (buttonView.getId() == R.id.ck_wlan) {
			Utils.setWlanStatus(this, isChecked);
		}
	}
  
	private void setWifiList() {
        ArrayList<WifiConnect> wifiList = new ArrayList<WifiConnect>();
        WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
        int state = mWifiManager.getWifiState();
        String SSID = "";
        if (state==WifiManager.WIFI_STATE_ENABLED || state==WifiManager.WIFI_STATE_ENABLING) {
        	SSID = wifiInfo.getSSID();
        } else {
    		WifiListAdapter wifiAdapter = new WifiListAdapter(this, mWifiManager, wifiList);
    		lv_wifi.setAdapter(wifiAdapter);
        	return;
        }
        
		mWifiManager.startScan();
    	ArrayList<ScanResult> newResultList = getResultList();
    	List<WifiConfiguration> configList = mWifiManager.getConfiguredNetworks();
    	for(int i=0; i<newResultList.size(); i++) {
    		ScanResult item = newResultList.get(i);
    		WifiConnect wifi = new WifiConnect();
    		wifi.SSID = item.SSID;
    		wifi.level = WifiManager.calculateSignalLevel(item.level, 4);
    		if (SSID.indexOf(wifi.SSID) >= 0) {
    			wifi.status = true;
    		}
    		if (item.capabilities.toUpperCase().indexOf("WPA2") >= 0) {
    			wifi.type = 4;
    		} else if (item.capabilities.toUpperCase().indexOf("WPA") >= 0) {
    			wifi.type = WifiConfiguration.KeyMgmt.WPA_PSK;
    		} else {
    			wifi.type = WifiConfiguration.KeyMgmt.NONE;
    		}
        	for(int j=0; j<configList.size(); j++) {
        		if (configList.get(j).SSID.indexOf(wifi.SSID) >= 0) {
        			wifi.networkId = configList.get(j).networkId;
        			break;
        		}
        	}
        	wifiList.add(wifi);
    	}
		WifiListAdapter wifiAdapter = new WifiListAdapter(this, mWifiManager, wifiList);
		lv_wifi.setAdapter(wifiAdapter);
	}
	
	private ArrayList<ScanResult> getResultList() {
    	List<ScanResult> resultList = mWifiManager.getScanResults();
    	ArrayList<ScanResult> newResultList = new ArrayList<ScanResult>();
    	for(int i=0; i<resultList.size(); i++) {
    		ScanResult item = resultList.get(i);
    		int j;
        	for(j=0; j<newResultList.size(); j++) {
        		ScanResult newItem = newResultList.get(j);
        		if (item.SSID.equals(newItem.SSID)) {
        			if (item.level>newItem.level) {
            			newResultList.set(j, item);
        			}
        			break;
        		}
        	}
        	if (j >= newResultList.size()) {
        		newResultList.add(item);
        	}
    	}
    	return newResultList;
	}

	private Runnable mRefresh = new Runnable() {
		@Override
		public void run() {
			//scanWifi();
			setWifiList();
			mHandler.postDelayed(this, 3000);;
		}
	};

	@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
	private void scanWifi() {
		tv_result.setVisibility(View.VISIBLE);
		tv_config.setVisibility(View.VISIBLE);
		mWifiManager.startScan();
    	ArrayList<ScanResult> newResultList = getResultList();
    	String resultStr = String.format("扫描发现%d个wifi信息\n", newResultList.size());
    	for(int i=0; i<newResultList.size(); i++) {
    		ScanResult item = newResultList.get(i);
    		resultStr = String.format("%s名称%s,MAC地址%s,描述%s,时间%s,信号强度%d,频率%dMHz\n", 
    				resultStr, item.SSID, item.BSSID, item.capabilities, Utils.getTimeStamp(item.timestamp), item.level, item.frequency);
    	}
		tv_result.setText(resultStr);

    	List<WifiConfiguration> configList = mWifiManager.getConfiguredNetworks();
    	String configStr = String.format("扫描发现%d个wifi配置\n", configList.size());
    	for(int i=0; i<configList.size(); i++) {
    		WifiConfiguration item = configList.get(i);
    		configStr = String.format("%s名称%s,MAC地址%s,网络编号%d,状态%d,密码%s,优先级%d,类型%s\n", 
    				configStr, item.SSID, item.BSSID, item.networkId, item.status, item.preSharedKey, item.priority, item.allowedKeyManagement);
    	}
    	tv_config.setText(configStr);
	}

	@Override
	public void onInput(String ssid, String password, int type) {
		WifiConfiguration config = createWifiInfo(ssid, password, type);
		int netId = mWifiManager.addNetwork(config);
		if (netId == -1) {
			Toast.makeText(this, "密码错误", Toast.LENGTH_LONG).show();
		} else {
			mWifiManager.enableNetwork(netId, true);
		}
	}

	private WifiConfiguration createWifiInfo(String ssid, String password, int type) {
		WifiConfiguration config = new WifiConfiguration();
		config.SSID = "\"" + ssid + "\"";
		if (type == WifiConfiguration.KeyMgmt.NONE) {  //明文密码
			config.wepKeys[0] = "";
			config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
			config.wepTxKeyIndex = 0;
		} else {  //WPA加密或者WPA2加密
			config.preSharedKey = "\"" + password + "\"";
			config.hiddenSSID = true;
			config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
			config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
			config.allowedKeyManagement.set(type);
			config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
			config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
			config.status = WifiConfiguration.Status.ENABLED;
		}
		return config;
	}

}

下面是个人热点管理的代码示例:

import java.util.ArrayList;
import java.util.BitSet;

import com.example.exmnetwork.adapter.ClientListAdapter;
import com.example.exmnetwork.bean.ClientScanResult;
import com.example.exmnetwork.util.ApUtil;

import android.app.Activity;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.Selection;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

public class ApActivity extends Activity implements OnClickListener,OnLongClickListener,OnCheckedChangeListener {

	private static final String TAG = "ApActivity";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_ap);
		initView();
		initWifi();
	}

	private CheckBox ck_ap_switch;
	private TextView tv_ap_connect, tv_ap_device;
	private EditText et_ap_name, et_ap_password;
	private Spinner sp_ap_des;
	private Button btn_ap_cancel, btn_ap_save; 
	private ListView lv_client;
    private WifiManager mWifiManager;
    private WifiConfiguration mApConfig;
    private int mDesType = 0, mTmpDesType = 0;
    private String mApName = "", mApPassword = "";
    
	private void initView() {
		ck_ap_switch = (CheckBox) findViewById(R.id.ck_ap_switch);
		tv_ap_connect = (TextView) findViewById(R.id.tv_ap_connect);
		tv_ap_device = (TextView) findViewById(R.id.tv_ap_device);
		et_ap_name = (EditText) findViewById(R.id.et_ap_name);
		et_ap_password = (EditText) findViewById(R.id.et_ap_password);
		btn_ap_cancel = (Button) findViewById(R.id.btn_ap_cancel);
		btn_ap_save = (Button) findViewById(R.id.btn_ap_save);
		lv_client = (ListView) findViewById(R.id.lv_client);

		btn_ap_cancel.setOnClickListener(this);
		btn_ap_save.setOnClickListener(this);
		et_ap_name.setOnLongClickListener(this);
		et_ap_password.setOnLongClickListener(this);
		et_ap_name.addTextChangedListener(new MyTextWatcher(et_ap_name, et_ap_password));
		et_ap_password.addTextChangedListener(new MyTextWatcher(et_ap_password, sp_ap_des));

		sp_ap_des = (Spinner) findViewById(R.id.sp_ap_des);
		ArrayAdapter<String> starAdapter = new ArrayAdapter<String>(this,
				R.layout.spinner_item, desTextArray);
		starAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
		sp_ap_des.setAdapter(starAdapter);
		sp_ap_des.setSelection(mDesType);
		sp_ap_des.setPrompt("请选择加密方式");
		sp_ap_des.setOnItemSelectedListener(new DesSelectedListener());

	}

	private String[] desTextArray = {"无", "WPA PSK", "WPA2 PSK"};
	private int[] desTypeArray = {WifiConfiguration.KeyMgmt.NONE, 
			WifiConfiguration.KeyMgmt.WPA_PSK, 4};
	private ArrayList<ClientScanResult> mClientArray = new ArrayList<ClientScanResult>();
	
	class DesSelectedListener implements OnItemSelectedListener {
		@Override
		public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
			mTmpDesType = arg2;
		}

		@Override
		public void onNothingSelected(AdapterView<?> arg0) {
		}
	}

	class MyTextWatcher implements TextWatcher {
		private EditText mThisView = null;
		private View mNextView = null;
		 
		public MyTextWatcher(EditText vThis, View vNext) {
			super();
			mThisView = vThis;
			if (vNext != null) {
				mNextView = vNext;
			}
		}
		
		@Override
		public void beforeTextChanged(CharSequence s, int start, int count, int after) {
		}

		@Override
		public void onTextChanged(CharSequence s, int start, int before, int count) {
		}

		@Override
		public void afterTextChanged(Editable s) {
			String str = s.toString();
			if (str.indexOf("\r") >= 0 || str.indexOf("\n") >= 0) {
				mThisView.setText(str.replace("\r", "").replace("\n", ""));
				if (mNextView != null) {
					mNextView.requestFocus();
					if (mNextView instanceof EditText) {
						EditText et = (EditText)mNextView;
						Editable edit = et.getText();
						Selection.setSelection(edit, edit.length());
					}
				}
			}
		}
	 }
	private void initWifi() {
        mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        mApConfig = new WifiConfiguration();
        int apStatus = ApUtil.getWifiApState(mWifiManager);
		if (apStatus == ApUtil.WIFI_AP_STATE_ENABLED) {
			readSystemAp();
		} else {
			mApName = Build.SERIAL;
			mApPassword = "12345678";
			mDesType = mTmpDesType = WifiConfiguration.KeyMgmt.WPA_PSK;
		}

		mApConfig.SSID = mApName;
        et_ap_name.setText(mApName);
        et_ap_password.setText(mApPassword);
		sp_ap_des.setSelection(mDesType);
        refreshStatus();
        if (apStatus==ApUtil.WIFI_AP_STATE_ENABLING || apStatus==ApUtil.WIFI_AP_STATE_ENABLED) {
        	ck_ap_switch.setChecked(true);
        }
		ck_ap_switch.setOnCheckedChangeListener(this);
	}
	
	private void readSystemAp() {
		WifiConfiguration apConfig = ApUtil.getWifiApConfiguration(mWifiManager);
		if (apConfig!=null && apConfig.SSID!=null && apConfig.allowedKeyManagement!=null) {
			mApName = apConfig.SSID;
			BitSet bit = apConfig.allowedKeyManagement;
			if (bit.get(WifiConfiguration.KeyMgmt.NONE) == true) {
				mDesType = mTmpDesType = WifiConfiguration.KeyMgmt.NONE;
				mApPassword = apConfig.wepKeys[0];
			} else if (bit.get(WifiConfiguration.KeyMgmt.WPA_PSK) == true) {
				mDesType = mTmpDesType = WifiConfiguration.KeyMgmt.WPA_PSK;
				mApPassword = apConfig.preSharedKey;
			} else if (bit.get(4) == true) {
				mDesType = mTmpDesType = 2;  //desTypeArray第三个元素的值就是4
				mApPassword = apConfig.preSharedKey;
			}
		}
	}
	
	@Override
	public void onStart() {
		mRefreshHandler.postDelayed(mStatusRefresh, 25);
		mRefreshHandler.postDelayed(mClientRefresh, 50);
		super.onStart();
	}
	
	@Override
	public void onStop() {
		mRefreshHandler.removeCallbacks(mStatusRefresh);
		mRefreshHandler.removeCallbacks(mClientRefresh);
		super.onStop();
	}

	private final Handler mRefreshHandler = new Handler();
	private Runnable mStatusRefresh = new Runnable() {
		@Override
		public void run() {
	        refreshStatus();
			mRefreshHandler.postDelayed(this, 1000);
		}
	};

	private Runnable mClientRefresh = new Runnable() {
		@Override
		public void run() {
	        (new ClientScanThread()).start(); 
			mRefreshHandler.postDelayed(this, 3000);
		}
	};

	private Runnable mReOpenRefresh = new Runnable() {
		@Override
		public void run() {
			int ap_status = ApUtil.getWifiApState(mWifiManager);
	        if (ap_status == ApUtil.WIFI_AP_STATE_DISABLED) {
				ck_ap_switch.setChecked(true);
	        } else {
				mRefreshHandler.postDelayed(this, 2000);
	        }
		}
	};

	private int mLastStatus = 20;
	private void refreshStatus() {
        int apStatus = ApUtil.getWifiApState(mWifiManager);
        if (apStatus == mLastStatus) {
        	return;
        }
        Log.d(TAG, "apStatus="+apStatus+", mLastStatus="+mLastStatus+", mName="+mApName);
        mLastStatus = apStatus;
        if (apStatus == ApUtil.WIFI_AP_STATE_ENABLING) {
        	tv_ap_connect.setText("正在开启热点......");
        	tv_ap_connect.setVisibility(View.VISIBLE);
        	ck_ap_switch.setEnabled(false);
        } else if (apStatus == ApUtil.WIFI_AP_STATE_ENABLED) {
        	tv_ap_connect.setText("热点"+mApName+"已开启");
        	tv_ap_connect.setVisibility(View.VISIBLE);
        	ck_ap_switch.setEnabled(true);
        	if (ck_ap_switch.isChecked() == false) {
            	ck_ap_switch.setChecked(true);
        	}
        } else if (apStatus==ApUtil.WIFI_AP_STATE_DISABLING) {
        	tv_ap_connect.setText("正在断开热点......");
        	tv_ap_connect.setVisibility(View.VISIBLE);
        	ck_ap_switch.setEnabled(false);
        } else {
        	tv_ap_connect.setVisibility(View.GONE);
        	ck_ap_switch.setEnabled(true);
        	if (ck_ap_switch.isChecked() == true) {
            	ck_ap_switch.setChecked(false);
        	}
        }
	}
	
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btn_ap_cancel:
			et_ap_name.setText(mApName);
			et_ap_password.setText(mApPassword);
			sp_ap_des.setSelection(mDesType);
			Toast.makeText(this, "已取消本次热点设置", Toast.LENGTH_LONG).show();
			break;
		case R.id.btn_ap_save:
			if (et_ap_name.getText().length() < 4) {
				Toast.makeText(this, "热点名称长度需不小于四位", Toast.LENGTH_LONG).show();
				return;
			}
			if (mTmpDesType!=0 && et_ap_password.getText().length() < 8) {
				Toast.makeText(this, "热点密码长度需不小于八位", Toast.LENGTH_LONG).show();
				return;
			}
			mApName = et_ap_name.getText().toString();
			mApPassword = et_ap_password.getText().toString();
			mDesType = mTmpDesType;
			Toast.makeText(this, "已保存本次热点设置", Toast.LENGTH_LONG).show();
			if (ck_ap_switch.isChecked() == true) {  ////只有当前已开启热点的,才需要断开并重连。当前未开启热点的,保存设置后不自动开热点
				ck_ap_switch.setChecked(false);
				mRefreshHandler.postDelayed(mReOpenRefresh, 1000);
			}
			break;
		default:
			break;
		}
	}
	
	@Override
	public boolean onLongClick(View v) {
		if (v.getId() == R.id.et_ap_name) {
			et_ap_name.setText("");
		} else if (v.getId() == R.id.et_ap_password) {
			et_ap_password.setText("");
		}
		return false;
	}
	
	private void resetApConfig() {
		mApConfig.allowedKeyManagement.clear();
		mApConfig.SSID = mApName;
		if (mDesType == 0) {
			mApConfig.preSharedKey = "";
	        mApConfig.wepKeys[0] = mApPassword;
	        mApConfig.wepTxKeyIndex = 0;
		} else {
			mApConfig.allowedKeyManagement.set(desTypeArray[mDesType]);
			mApConfig.preSharedKey = mApPassword;
	        mApConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
	        mApConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
	        mApConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
	        mApConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
	        mApConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
	        mApConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
		}
	}
	
	@Override
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
		int id = buttonView.getId();
		if (id == R.id.ck_ap_switch) {
			String desc = "";
			if (isChecked == false) {
				desc = ApUtil.setWifiApEnabled(mWifiManager, mApConfig, isChecked);
			} else {
				mDesType = mTmpDesType;
				resetApConfig();
				desc = ApUtil.setWifiApEnabled(mWifiManager, mApConfig, isChecked);
			}
        	Log.d(TAG, desc);
			if (desc!=null && desc.length()>0) {
				Toast.makeText(this, desc, Toast.LENGTH_LONG).show();
				ck_ap_switch.setChecked(!isChecked);
			}
		}
	}

	private class ClientScanThread extends Thread {
		@Override
		public void run() {
			mClientArray = ApUtil.getClientList(true);
			Message message = mScanHandler.obtainMessage();
			message.what = 99;
			mScanHandler.sendMessage(message);
		}
	}
	
	private int mClientCount = 9;
	
	private Handler mScanHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			mScanHandler.removeMessages(99);
			Log.d(TAG, "mClientArray.size()="+mClientArray.size());
			int ap_status = ApUtil.getWifiApState(mWifiManager);
	        if (ap_status!=ApUtil.WIFI_AP_STATE_ENABLING && ap_status!=ApUtil.WIFI_AP_STATE_ENABLED) {
	        	mClientArray.clear();
	        } else if (mClientArray == null) {
	        	mClientArray = new ArrayList<ClientScanResult>();
	        }
	        if (mClientCount!=9 && mClientCount!=mClientArray.size()) { //连续两次设备数量相同才更新,避免Android间歇性抽风
		        mClientCount = mClientArray.size();
	        	return;
	        }
			String text = String.format("已连接设备(%d)", mClientArray.size());
			tv_ap_device.setText(text);

			ClientListAdapter clientAdapter = new ClientListAdapter(ApActivity.this, mClientArray);
			lv_client.setAdapter(clientAdapter);
		}
	};

}

点击下载本文用到的网络检测与连接以及个人热点管理的工程代码 点此查看Android开发笔记的完整目录

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年02月09日,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 检测网络
  • 连接wifi
  • 反射reflect
  • 个人热点
  • 代码示例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档