您的位置:首页 > 移动开发 > Android开发

android4.1.1 Settings WIFI模块浅析

2017-06-07 20:26 183 查看
http://blog.csdn.net/cljfqyd/article/details/8863694

版权声明:本文为博主原创文章,未经博主允许不得转载。

[java]
view plain
copy

<span style="font-family: Arial, Helvetica, sans-serif;">Settings 中的WIFI功能主要在package/Settings/src/com/android/wifi/WifiSettings实现</span>  

首先我们来看下WifiSettings类声明

[java]
view plain
copy

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 plain
copy

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 plain
copy

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 plain
copy

public class WifiManager {  
   .....  
 public WifiManager(IWifiManager service, Handler handler) {  
        mService = service;  
        mHandler = handler;  
    }  
   ......  
}  

从IWifiManager 可知道,它是通过远程调用,也就是基于RPC原理(有时间再总结一下)。

为了保证Settings和Wifi相互交互,注册相应的监听对象。

[java]
view plain
copy

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 plain
copy

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 plain
copy

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状态。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: