首页 > 代码库 > android4.1.1 Settings WIFI模块浅析
android4.1.1 Settings WIFI模块浅析
[java] view plaincopy
<span style="font-family: Arial, Helvetica, sans-serif;">Settings 中的WIFI功能主要在package/Settings/src/com/android/wifi/WifiSettings实现</span>
首先我们来看下WifiSettings类声明
[java] view plaincopy
public class WifiSettings extends SettingsPreferenceFragment
implements DialogInterface.OnClickListener {
......
}
继承SettingsPreferenceFragment,可见它是一个Fragment我们看到源码中的描述是这样的
/**
* Two types of UI are provided here.
*
* The first is for "usual Settings", appearing as any other Setup fragment.
*
* The second is for Setup Wizard, with a simplified interface that hides the action bar
* and menus.
*/
一、注册广播,接受相关wifi信息变化
WifiSettins类主要负责监测wifi状态,以及加载各个连接点,并负责Fragment界面的显示。
在WifiSettings类中比较重要的一个类是WifiManager(稍后再说,一步一步来).
在WifiSettings构造函数中初始化一个BroadcastReceiver,该BroadcastReceiver监测外部广播
[java] view plaincopy
public class WifiSettings extends SettingsPreferenceFragment
implements DialogInterface.OnClickListener {
......
public WifiSettings() {
mFilter = new IntentFilter();//添加过滤器
mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
handleEvent(context, intent);//事件处理函数
}
};
mScanner = new Scanner();
}
......
@Override
public void onResume() {
super.onResume();
if (mWifiEnabler != null) {
mWifiEnabler.resume();
}
getActivity().registerReceiver(mReceiver, mFilter);//在onResume注册广播,获得相关wifi信息
if (mKeyStoreNetworkId != INVALID_NETWORK_ID &&
KeyStore.getInstance().state() == KeyStore.State.UNLOCKED) {
mWifiManager.connect(mChannel, mKeyStoreNetworkId, mConnectListener);
}
mKeyStoreNetworkId = INVALID_NETWORK_ID;
updateAccessPoints();
}
......
@Override
public void onPause() {
super.onPause();
if (mWifiEnabler != null) {
mWifiEnabler.pause();
}
getActivity().unregisterReceiver(mReceiver);//在onPause注销广播
mScanner.pause();
}
......
}
广播的处理事件代码:
[java] view plaincopy
private void handleEvent(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN));
} else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) ||
WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) ||
WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
updateAccessPoints();
} else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
//Ignore supplicant state changes when network is connected
//TODO: we should deprecate SUPPLICANT_STATE_CHANGED_ACTION and
//introduce a broadcast that combines the supplicant and network
//network state change events so the apps dont have to worry about
//ignoring supplicant state change when network is connected
//to get more fine grained information.
SupplicantState state = (SupplicantState) intent.getParcelableExtra(
WifiManager.EXTRA_NEW_STATE);
if (!mConnected.get() && SupplicantState.isHandshakeState(state)) {
updateConnectionState(WifiInfo.getDetailedStateOf(state));
}
} else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
WifiManager.EXTRA_NETWORK_INFO);
mConnected.set(info.isConnected());
changeNextButtonState(info.isConnected());
updateAccessPoints();
updateConnectionState(info.getDetailedState());
if (mAutoFinishOnConnection && info.isConnected()) {
getActivity().finish();
return;
}
} else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
updateConnectionState(null);
}
}
二、WifiMananger类是是操作wifi的核心类
WifiManager定义wifi各种状态、wifi Action、网络配置等
[java] view plaincopy
public class WifiManager {
.....
public WifiManager(IWifiManager service, Handler handler) {
mService = service;
mHandler = handler;
}
......
}
从IWifiManager 可知道,它是通过远程调用,也就是基于RPC原理(有时间再总结一下)。
为了保证Settings和Wifi相互交互,注册相应的监听对象。
[java] view plaincopy
public class WifiSettings extends SettingsPreferenceFragment
implements DialogInterface.OnClickListener {
......
private WifiManager.ActionListener mConnectListener;//连接
private WifiManager.ActionListener mSaveListener;//保存
private WifiManager.ActionListener mForgetListener;//清除保存
......
//继承SettingsPreferenceFragment并从写 onActivityCreated方法
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// We don‘t call super.onActivityCreated() here, since it assumes we already set up
// Preference (probably in onCreate()), while WifiSettings exceptionally set it up in
// this method.
mP2pSupported = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT);
mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
mChannel = mWifiManager.initialize(getActivity(), getActivity().getMainLooper(), null);
mConnectListener = new WifiManager.ActionListener() {
public void onSuccess() {//连接成功
}
public void onFailure(int reason) {//连接失败
Toast.makeText(getActivity(),
R.string.wifi_failed_connect_message,
Toast.LENGTH_SHORT).show();
}
};
mSaveListener = new WifiManager.ActionListener() {
public void onSuccess() {//保存成功
}
public void onFailure(int reason) {//保存失败
Toast.makeText(getActivity(),
R.string.wifi_failed_save_message,
Toast.LENGTH_SHORT).show();
}
};
mForgetListener = new WifiManager.ActionListener() {
public void onSuccess() {//清除保存成功
}
public void onFailure(int reason) {//清除保存失败
Toast.makeText(getActivity(),
R.string.wifi_failed_forget_message,
Toast.LENGTH_SHORT).show();
}
};
if (savedInstanceState != null
&& savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) {
mDlgEdit = savedInstanceState.getBoolean(SAVE_DIALOG_EDIT_MODE);
mAccessPointSavedState = savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE);
}
final Activity activity = getActivity();
final Intent intent = activity.getIntent();
// first if we‘re supposed to finish once we have a connection
mAutoFinishOnConnection = intent.getBooleanExtra(EXTRA_AUTO_FINISH_ON_CONNECT, false);
if (mAutoFinishOnConnection) {
// Hide the next button
if (hasNextButton()) {
getNextButton().setVisibility(View.GONE);
}
final ConnectivityManager connectivity = (ConnectivityManager)
getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity != null
&& connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected()) {
activity.finish();
return;
}
}
// if we‘re supposed to enable/disable the Next button based on our current connection
// state, start it off in the right state
mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false);
if (mEnableNextOnConnection) {
if (hasNextButton()) {
final ConnectivityManager connectivity = (ConnectivityManager)
getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity != null) {
NetworkInfo info = connectivity.getNetworkInfo(
ConnectivityManager.TYPE_WIFI);
changeNextButtonState(info.isConnected());
}
}
}
addPreferencesFromResource(R.xml.wifi_settings);//加载布局
if (mSetupWizardMode) {
getView().setSystemUiVisibility(
View.STATUS_BAR_DISABLE_BACK |
View.STATUS_BAR_DISABLE_HOME |
View.STATUS_BAR_DISABLE_RECENT |
View.STATUS_BAR_DISABLE_NOTIFICATION_ALERTS |
View.STATUS_BAR_DISABLE_CLOCK);
}
// On/off switch is hidden for Setup Wizard
if (!mSetupWizardMode) {
Switch actionBarSwitch = new Switch(activity);
if (activity instanceof PreferenceActivity) {
PreferenceActivity preferenceActivity = (PreferenceActivity) activity;
if (preferenceActivity.onIsHidingHeaders() || !preferenceActivity.onIsMultiPane()) {
final int padding = activity.getResources().getDimensionPixelSize(
R.dimen.action_bar_switch_padding);
actionBarSwitch.setPadding(0, 0, padding, 0);
activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
ActionBar.DISPLAY_SHOW_CUSTOM);
activity.getActionBar().setCustomView(actionBarSwitch, new ActionBar.LayoutParams(
ActionBar.LayoutParams.WRAP_CONTENT,
ActionBar.LayoutParams.WRAP_CONTENT,
Gravity.CENTER_VERTICAL | Gravity.RIGHT));
}
}
mWifiEnabler = new WifiEnabler(activity, actionBarSwitch);
}
mEmptyView = (TextView) getView().findViewById(android.R.id.empty);
getListView().setEmptyView(mEmptyView);
if (!mSetupWizardMode) {
registerForContextMenu(getListView());
}
setHasOptionsMenu(true);
// After confirming PreferenceScreen is available, we call super.
super.onActivityCreated(savedInstanceState);
}
......
}
三、用户on/off交互
用户通过Switch 开关按钮进行对wifi打开和关闭
[java] view plaincopy
public class WifiSettings extends SettingsPreferenceFragment
implements DialogInterface.OnClickListener {
......
public void onActivityCreated(Bundle savedInstanceState) {
......
// On/off switch is hidden for Setup Wizard
if (!mSetupWizardMode) {
Switch actionBarSwitch = new Switch(activity);
if (activity instanceof PreferenceActivity) {
PreferenceActivity preferenceActivity = (PreferenceActivity) activity;
if (preferenceActivity.onIsHidingHeaders() || !preferenceActivity.onIsMultiPane()) {
final int padding = activity.getResources().getDimensionPixelSize(
R.dimen.action_bar_switch_padding);
actionBarSwitch.setPadding(0, 0, padding, 0);
activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
ActionBar.DISPLAY_SHOW_CUSTOM);
activity.getActionBar().setCustomView(actionBarSwitch, new ActionBar.LayoutParams(
ActionBar.LayoutParams.WRAP_CONTENT,
ActionBar.LayoutParams.WRAP_CONTENT,
Gravity.CENTER_VERTICAL | Gravity.RIGHT));
}
}
mWifiEnabler = new WifiEnabler(activity, actionBarSwitch);//将actionBarSwitch传递给WifiEnabler
}
......
}
......
}
WifiEnabler接受一个Switch对象和,并该对象进行操作
我们可以看下WifiEnabler这个类
[java] view plaincopy
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.NetworkInfo;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.provider.Settings;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.Toast;
import com.android.settings.R;
import com.android.settings.WirelessSettings;
import java.util.concurrent.atomic.AtomicBoolean;
public class WifiEnabler implements CompoundButton.OnCheckedChangeListener {
private final Context mContext;
private Switch mSwitch;
private AtomicBoolean mConnected = new AtomicBoolean(false);
private final WifiManager mWifiManager;
private boolean mStateMachineEvent;
private final IntentFilter mIntentFilter;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
handleWifiStateChanged(intent.getIntExtra(
WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
} else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
if (!mConnected.get()) {
handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState)
intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
}
} else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
WifiManager.EXTRA_NETWORK_INFO);
mConnected.set(info.isConnected());
handleStateChanged(info.getDetailedState());
}
}
};
public WifiEnabler(Context context, Switch switch_) {
mContext = context;
mSwitch = switch_;
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
// The order matters! We really should not depend on this. :(
mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
}
public void resume() {
// Wi-Fi state is sticky, so just let the receiver update UI
mContext.registerReceiver(mReceiver, mIntentFilter);
mSwitch.setOnCheckedChangeListener(this);
}
public void pause() {
mContext.unregisterReceiver(mReceiver);
mSwitch.setOnCheckedChangeListener(null);
}
public void setSwitch(Switch switch_) {
if (mSwitch == switch_) return;
mSwitch.setOnCheckedChangeListener(null);
mSwitch = switch_;
mSwitch.setOnCheckedChangeListener(this);
final int wifiState = mWifiManager.getWifiState();
boolean isEnabled = wifiState == WifiManager.WIFI_STATE_ENABLED;
boolean isDisabled = wifiState == WifiManager.WIFI_STATE_DISABLED;
mSwitch.setChecked(isEnabled);
mSwitch.setEnabled(isEnabled || isDisabled);
}
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//Do nothing if called as a result of a state machine event
if (mStateMachineEvent) {
return;
}
// Show toast message if Wi-Fi is not allowed in airplane mode
if (isChecked && !WirelessSettings.isRadioAllowed(mContext, Settings.System.RADIO_WIFI)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
// Reset switch to off. No infinite check/listenenr loop.
buttonView.setChecked(false);
}
// Disable tethering if enabling Wifi
int wifiApState = mWifiManager.getWifiApState();
if (isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
(wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
mWifiManager.setWifiApEnabled(null, false);
}
if (mWifiManager.setWifiEnabled(isChecked)) {
// Intent has been taken into account, disable until new state is active
mSwitch.setEnabled(false);
} else {
// Error
Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
}
}
private void handleWifiStateChanged(int state) {
switch (state) {
case WifiManager.WIFI_STATE_ENABLING:
mSwitch.setEnabled(false);
break;
case WifiManager.WIFI_STATE_ENABLED:
setSwitchChecked(true);
mSwitch.setEnabled(true);
break;
case WifiManager.WIFI_STATE_DISABLING:
mSwitch.setEnabled(false);
break;
case WifiManager.WIFI_STATE_DISABLED:
setSwitchChecked(false);
mSwitch.setEnabled(true);
break;
default:
setSwitchChecked(false);
mSwitch.setEnabled(true);
break;
}
}
private void setSwitchChecked(boolean checked) {
if (checked != mSwitch.isChecked()) {
mStateMachineEvent = true;
mSwitch.setChecked(checked);
mStateMachineEvent = false;
}
}
private void handleStateChanged(@SuppressWarnings("unused") NetworkInfo.DetailedState state) {
// After the refactoring from a CheckBoxPreference to a Switch, this method is useless since
// there is nowhere to display a summary.
// This code is kept in case a future change re-introduces an associated text.
/*
// WifiInfo is valid if and only if Wi-Fi is enabled.
// Here we use the state of the switch as an optimization.
if (state != null && mSwitch.isChecked()) {
WifiInfo info = mWifiManager.getConnectionInfo();
if (info != null) {
//setSummary(Summary.get(mContext, info.getSSID(), state));
}
}
*/
}
}
WifiEnabler实现了CompoundButton.OnCheckedChangeListener接口类,可见它也是一个监听器,并且在构造函数中通过接受一个switch对象去观察switch状态。
android4.1.1 Settings WIFI模块浅析