zoukankan      html  css  js  c++  java
  • Android WIFI 分析(二)

    本文介绍Wifi 分析线路二:在Setting中打开WiFi功能、扫描网络以及连接网络的流程。

    WifiSettings 无线网络设置界面

    WifiEnabler 相当于无线网络设置开关

    WifiDialog 显示的无线网络配置信息由WifiConfigController 来控制和管理

    Scanner 用于处理和无线网络扫描相关的工作

    1、Settings 操作

    无线网络设置界面UI 初始化过程中,WifiSettings 的onActivityCreated() 方法被调用:

        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
    
            mWifiTracker =
                    new WifiTracker(getActivity(), this, mBgThread.getLooper(), true, true, false);
            mWifiManager = mWifiTracker.getManager();
        }

    WifiTracker 构造函数调用:

        WifiTracker(Context context, WifiListener wifiListener, Looper workerLooper,
                boolean includeSaved, boolean includeScans, boolean includePasspoints,
                WifiManager wifiManager, ConnectivityManager connectivityManager,
                Looper currentLooper) {
         //添加多个广播事件,在startTracker() 方法中进行注册
            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);
    
            mNetworkRequest = new NetworkRequest.Builder()
                    .clearCapabilities()
                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                    .build();
        }

    WifiSettings 的onStart() 方法创建WifiEnabler:

        public void onStart() {
            // On/off switch is hidden for Setup Wizard (returns null)
            mWifiEnabler = createWifiEnabler();
        }
    
         WifiEnabler createWifiEnabler() {
            final SettingsActivity activity = (SettingsActivity) getActivity();
            return new WifiEnabler(activity, activity.getSwitchBar());
        }

    WifiEnabler 的构造函数,添加广播事件:

        public WifiEnabler(Context context, SwitchBar switchBar) {
            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);
    
            setupSwitchBar();
        }

    WIFI_STATE_CHANGED_ACTION:反映WiFi 功能所对应的状态,包括WIFI_STATE_DISABLED(Wifi 功能已被关闭)、WIFI_STATE_DISABLING(Wifi 功能正在关闭中)、WIFI_STATE_ENABLED(Wifi 功能已被打开)、WIFI_STATE_ENABLING(Wifi 功能正在打开中)、WIFI_STATE_UNKNOWN(Wifi 功能状态未知)。

    SUPPLICANT_STATE_CHANGED_ACTION:表示WPAS 的状态发生了变化。

    NETWORK_STATE_CHANGED_ACTION:表示WIFI 连接状态发生变化,其携带的信息一般是NetworkInfo 对象。

    WifiSettings 和 WifiEnabler 的设置的广播接收对象在onResume() 的方法中被注册:

        public void onResume() {
            final Activity activity = getActivity();
            if (mWifiEnabler != null) {
                mWifiEnabler.resume(activity); //调用WifiEnabler 类
            }
    
            mWifiTracker.startTracking(); //调用framework WifiTracker 类
            activity.invalidateOptionsMenu();
        }

    WifiEnabler 类的resume() 方法如下:

        public void resume(Context context) {
            mContext = context;
            // Wi-Fi state is sticky, so just let the receiver update UI
            mContext.registerReceiver(mReceiver, mIntentFilter); //注册构造函数中添加的三个广播事件
            if (!mListeningToOnSwitchChange) {
                mSwitchBar.addOnSwitchChangeListener(this);
                mListeningToOnSwitchChange = true;
            }
        }

    WifiTracker 类的startTracking() 方法如下:

        /**
         * Start tracking wifi networks.
         * Registers listeners and starts scanning for wifi networks. If this is not called
         * then forceUpdate() must be called to populate getAccessPoints().
         */
        public void startTracking() {
            resumeScanning();
            if (!mRegistered) {
                mContext.registerReceiver(mReceiver, mFilter); //注册构造函数中添加的广播事件
                // NetworkCallback objects cannot be reused. http://b/20701525 .
                mNetworkCallback = new WifiTrackerNetworkCallback();
                mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
            }
        }

    WifiEnabler 处理较多的及时WIFI_STATE_CHANGED_ACTION 广播,根据此广播信息更新Switch 的界面。

    2、启用WIFI 功能

    WifiEnabler 实现了SwitchBar 的onSwitchChangeListener 接口,故用户点击事件将触发WifiEnabler 的onSwitchChanged() 方法:

        public void onSwitchChanged(Switch switchView, boolean isChecked) {      
            // Disable tethering if enabling Wifi
            if (mayDisableTethering(isChecked)) {
                mWifiManager.setWifiApEnabled(null, false);
            }
        }

    WifiManager 的setWifiApEnabled() 方法将触发WifiService 开展一系列的动作,在此过程中,WifiManager 会通过发送广播的方法向外界发布一些信息,所以需重点关注广播事件的处理。

    WifiTracker 的广播接收对象的处理:

        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)) {
                    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)) {
                    mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS); //发送更新无线网络列表消息
                } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
                    NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
                            WifiManager.EXTRA_NETWORK_INFO);
                    mConnected.set(info.isConnected());
                    mMainHandler.sendEmptyMessage(MainHandler.MSG_CONNECTED_CHANGED);
                    mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
                    mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_NETWORK_INFO, info)
                            .sendToTarget();
                }
            }
        };

    WifiEnabler 的广播接收对象的处理:

        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());
                }
            }
        };

    1) 触发扫描

    当WIFI 功能被启用时,将收到WIFI_STATE_CHANGED_ACTION 广播,该广播的处理函数是WifiTracker 的updateWifiState() 方法:

        private void updateWifiState(int state) {
            mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_WIFI_STATE, state, 0).sendToTarget();
        } //向内部WrokHandler 对象发送消息

    MSG_UPDATE_WIFI_STATE 的处理:

                    case MSG_UPDATE_WIFI_STATE:
                        if (msg.arg1 == WifiManager.WIFI_STATE_ENABLED) {
                            if (mScanner != null) {
                                // We only need to resume if mScanner isn't null because
                                // that means we want to be scanning.
                                mScanner.resume(); //启动扫描
                            }
                        } else {
                            mLastInfo = null;
                            mLastNetworkInfo = null;
                            if (mScanner != null) {
                                mScanner.pause();
                            }
                        }
                        mMainHandler.obtainMessage(MainHandler.MSG_WIFI_STATE_CHANGED, msg.arg1, 0)
                                .sendToTarget(); //向内部MainHandler 对象发送消息
                        break;

    Scanner 也是WifiTracker 内部定义的一个Handler:

        class Scanner extends Handler {
            static final int MSG_SCAN = 0;
    
            void resume() {
                if (!hasMessages(MSG_SCAN)) {
                    sendEmptyMessage(MSG_SCAN);
                }
            }
    
            @Override
            public void handleMessage(Message message) {
                if (message.what != MSG_SCAN) return;
                if (mWifiManager.startScan()) { //发起扫描
                    mRetry = 0;
                } else if (++mRetry >= 3) { //扫描失败
                    mRetry = 0;
                    if (mContext != null) {
                        Toast.makeText(mContext, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();
                    }
                    return;
                }
                sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS); //每1秒发起一次扫描
            }
        }

    2) 更新AP 列表

    如果WPAS 扫描完毕,则WifiTracker 将收到SCAN_RESULTS_AVAILABLE_ACTION 广播,发送消息MSG_UPDATE_ACCESS_POINTS,WorkHandler 对此消息的处理如下:

                    case MSG_UPDATE_ACCESS_POINTS:
                        updateAccessPoints();
                        break;

    继而调用updateAccessPoints() 方法:

        private void updateAccessPoints() {
            final Collection<ScanResult> results = fetchScanResults(); //获取扫描结果
            final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
            // Pre-sort accessPoints to speed preference insertion
            Collections.sort(accessPoints); //创建AP 列表
            mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED); //向MainHandler 发送MSG_ACCESS_POINT_CHANGED

    3) 加入目标无线网络

    从列表中选择加入某个无线网络,处理用户选择AP 事件的方法是WifiSettings 的onPreferenceTreeClick() 方法:

        public boolean onPreferenceTreeClick(Preference preference) {
            if (preference instanceof LongPressAccessPointPreference) {
                mSelectedAccessPoint = ((LongPressAccessPointPreference) preference).getAccessPoint();
                /** Bypass dialog for unsecured, unsaved, and inactive networks */
                if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE &&
                        !mSelectedAccessPoint.isSaved() && !mSelectedAccessPoint.isActive()) { //对于没有安全设置的无线网络,直接连接它即可
                    mSelectedAccessPoint.generateOpenNetworkConfig();
                    connect(mSelectedAccessPoint.getConfig());
                } else if (mSelectedAccessPoint.isSaved()) {
                    showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_VIEW); //弹出无线密码输入框
                } else {
                    showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);
                }
            } else if (preference == mAddPreference) {
                onAddNetworkPressed();
            } 
        }

    当用户设置完目标无线网络(例如设置密码)后,点击“连接”按钮,将触发WifiSettings 的submit() 方法被调用:

        /* package */ void submit(WifiConfigController configController) {
            final WifiConfiguration config = configController.getConfig();
            if (config == null) {
            ......
            } else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) {
                mWifiManager.save(config, mSaveListener);
            } else {
                mWifiManager.save(config, mSaveListener);
                if (mSelectedAccessPoint != null) { // Not an "Add network"
                    connect(config); //连接目标无线网络
                }
            }
            mWifiTracker.resumeScanning();
        }

    至此,后续的工作就是等待并处理广播事件,如果一切顺利,将接收一个NETWORK_STATE_CHANGED_ACTION 广播事件以告知手机成功加入目标无线网络。

    和WifiManager 交互的几个重要函数以作下面分析重点:

    setWifiEnabled():启用WIFI 功能

    startScanActive():启动AP 扫描

    connect():连接至目标AP

  • 相关阅读:
    javaweb开发之解决全站乱码
    redis加入开机启动服务
    linux下安装memcache
    关于本地连接虚拟机(centos)里的mongodb失败问题
    oracle存储过程中返回一个程序集
    面向对象进阶(二)----------类的内置方法
    面向对象进阶(一)
    面向对象的三大特性之----------封装
    面向对象的三大特性之----------多态
    面向对象的三大特性之----------继承
  • 原文地址:https://www.cnblogs.com/kaifyou/p/6187908.html
Copyright © 2011-2022 走看看