[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状态。