检测网络
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这种笼统名称);
2、WifiManager没有阻止某个设备连接热点的方法,其他公开的api也没发现能够实现该功能的方法;
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开发笔记的完整目录