• Android11 Wifi开启、扫描和连接


    开启Wifi

    开启Wifi开关,Wifi开关是WifiEnablerWifiEnabler实现了 SwitchWidgetController.OnSwitchChangeListener监听,打开/关闭开关会回调至

    // 处理Switch 控件的状态变化事件   
     public boolean onSwitchToggled(boolean isChecked) {
            //Do nothing if called as a result of a state machine event
    		// 通过Switch.setEnabled 方法设置Switch 控件状态时,不需要再次禁止/允许Wi-Fi,否则将造成循环调用的后果
            if (mStateMachineEvent) {
                return true;
            }
            // Show toast message if Wi-Fi is not allowed in airplane mode
    		//如果在飞行模式时不允许单独使用Wi-Fi,使用Toast 信息框进行提示
            if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
                Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
                // Reset switch to off. No infinite check/listener loop.
                mSwitchWidget.setChecked(false);
                return false;
            }
    		
            if (isChecked) {
                mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_WIFI_ON);
            } else {
                // Log if user was connected at the time of switching off.
                mMetricsFeatureProvider.action(
                    mContext, SettingsEnums.ACTION_WIFI_OFF,
                    mConnected.get()
                );
            }
    		 //通过WifiManager.setWifiEnabled()开启/关闭wifi
            if (!mWifiManager.setWifiEnabled(isChecked)) {
                // Error
                mSwitchWidget.setEnabled(true);
                Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
            }
            return true;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    mWifiManager.setWifiEnabled(isChecked) 用于根据Switch控件的当前状态关闭或打开Wi-Fi。

    onCheckedChanged方法的开始部分使用了一个mStateMachineEvent变量,当该变量为true时直接跳出了onCheckedChanged方法。实际上,增加这个跳出条件的原因是因为Switch控件的状态变化可以有如下两种情况。

    • 直接单击Switch 控件。

    • 调用Switch.setChecked 方法。

    遗憾的是,上述两种情况都会触发onCheckedChanged方法的调用。不管是哪种方法使Switch控件的状态发生了变化,在onCheckedChanged中调用WifiManager.setWifiEnabled方法设置Wi-Fi状态都会再次触发 onCheckedChanged方法的调用。当再次调用onCheckedChanged 方法时就需要将mStateMachineEvent变量值设为true,这样onCheckedChanged方法在执行之初就会立刻返回(如果继续执行后面的代码,将会造成死循环),然后再将mStateMachineEvent变量值设为false。这样在下一次设置Wi-Fi状态时仍然可以继续执行onCheckedChanged方法了。

    用广播方式设置 Switch 控件的状态

     /packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java
    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(mWifiManager.getWifiState());
            } 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    对于Wi-Fi来说,这个广播接收器主要用于接收Wi-Fi的状态变化,并做进一步地处理。其中处理Wi-Fi状态变化的方法是handleWifiStateChanged

    private void handleWifiStateChanged(int state) {
        // Clear any previous state
        mSwitchWidget.setDisabledByAdmin(null);
    
        switch(state) {
            case WifiManager . WIFI_STATE_ENABLING : // 处理正在开启Wi-Fi的状态
            break;
            case WifiManager . WIFI_STATE_ENABLED : // 处理已经开启Wi-Fi的状态
            setSwitchBarChecked(true);
            mSwitchWidget.setEnabled(true);
            break;
            case WifiManager . WIFI_STATE_DISABLING : // 处理正在关闭Wi-Fi的状态
            break;
            case WifiManager . WIFI_STATE_DISABLED :  // 处理已经关闭Wi-Fi的状态
            setSwitchBarChecked(false);
            mSwitchWidget.setEnabled(true);
            break;
            default:                                   // 处理其他情况
            setSwitchBarChecked(false);
            mSwitchWidget.setEnabled(true);
        }
    }
    
    
    
     /packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java
    // 如果当前Wi-Fi 的状态与Switch 控件的状态不一致,改变Switch 控件的状态
    private void setSwitchBarChecked(boolean checked) {
        mStateMachineEvent = true;
        mSwitchWidget.setChecked(checked);
        mStateMachineEvent = false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    setSwitchChecked方法代码可以看出,在改变Switch控件状态之前(调用Switch.setChecked方法),先将mStateMachineEvent变量设为true。这就意味着在设置Switch控件状态时不会由于触发了onCheckedChanged方法而再次设置Wi-Fi状态,从而进行递归调用

    从这一点可以看出,WifiEnabler类中的广播接收器的目的只是为了设置Switch控件的状态,并不是为了设置Wi-Fi的状态。这么做的目的是当用户通过WifiManager.setWifiEnabled方法设置Wi-Fi状态时,尽管可以成功设置Wi-Fi的状态,但却无法改变Switch控件的状态,所以就会造成当前Wi-Fi状态与Switch控件的状态不一致的情况。为了解决这个问题,WifiManager.setWifiEnabled方法在设置Wi-Fi状态后,会发送一个广播(WifiManager.WIFI_STATE_CHANGED_ACTION),然后WifiEnabler类中的广播接收器就会接收到这个广播,并根据当前Wi-Fi的状态改变Switch控件的状态。

    扫描WiFi

    开始扫描的逻辑是从WifiSettings触发的。
    WifiTracker接收到wifi状态改变的广播以后,

    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)) { // 处理热点搜索完成的动作
                    mStaleScanResults = false;
                    mLastScanSucceeded =
                            intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, true);
    				// 更新搜索到的热点
                    fetchScansAndConfigsAndUpdateAccessPoints();
                } else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action)
                        || WifiManager.ACTION_LINK_CONFIGURATION_CHANGED.equals(action)) {
                    fetchScansAndConfigsAndUpdateAccessPoints();
                } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { // 网络状态变化动作
                    // TODO(sghuman): Refactor these methods so they cannot result in duplicate
                    // onAccessPointsChanged updates being called from this intent.
                    NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
                    updateNetworkInfo(info);
                    fetchScansAndConfigsAndUpdateAccessPoints();
                } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
                    updateNetworkInfo(/* networkInfo= */ null);
                }
            }
        };
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    如果wifi已经打开了,则开始扫描Wifi

        private void updateWifiState(int state) {
            if (isVerboseLoggingEnabled()) {
                Log.d(TAG, "updateWifiState: " + state);
            }
            if (state == WifiManager.WIFI\_STATE\_ENABLED) {
                synchronized (mLock) {
                    if (mScanner != null) {
    // We only need to resume if mScanner isn't null because
    // that means we want to be scanning.
                        mScanner.resume();
                    }
                }
            }
            mListener.onWifiStateChanged(state);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Scanner是用于扫描Wifi的类:

    class Scanner extends Handler {
        static final int MSG_SCAN = 0;
    
        private int mRetry = 0;
    
        // 通过resume 方法可以触发循环扫描热点
        void resume () {
            if (isVerboseLoggingEnabled()) {
                Log.d(TAG, "Scanner resume");
            }
            if (!hasMessages(MSG_SCAN)) {
                sendEmptyMessage(MSG_SCAN);
            }
        }
    
        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;
            }
            // 发送延迟消息,会每10 秒搜索一次热点
            sendEmptyMessageDelayed(MSG_SCAN, WIFI_RESCAN_INTERVAL_MS);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    首先会由WifiSettings类中创建的广播接收器处理WifiManager.NETWORK_STATE_CHANGED_ACTION 广播动作,然后在处理的过程中调用了Scanner.resume 方法开始扫描热点。当热点扫描完成后,系统发送 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION广播。

    调用fetchScansAndConfigsAndUpdateAccessPoints方法更新热点列表,具体更新是在updateAccessPoints()。这里的Scanner对象通过不断在Scanner. handleMessage方法中发送延迟消息,从而使系统每隔一定时间(10秒)就会扫描一次热点。

    private void fetchScansAndConfigsAndUpdateAccessPoints() {
    		// 获取所有搜索到的热点信息
            List newScanResults = mWifiManager.getScanResults();
    
            // Filter all unsupported networks from the scan result list
            final List filteredScanResults =
                    filterScanResultsByCapabilities(newScanResults);
    
    //        if (isVerboseLoggingEnabled()) {
                Log.i(TAG, "Fetched scan results: " + filteredScanResults);
    //        }
    		// 获取当前已经连接的热点信息
            List configs = mWifiManager.getConfiguredNetworks();
            updateAccessPoints(filteredScanResults, configs);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    updateAccessPoints(filteredScanResults, configs);中会创建已经连接的热点信息的AccessPointer对象,调用accessPoint.update更新状态信息,将热点信息添加到热点,最后回调WifiSettings中的onAccessPointsChanged()更新UI;

    连接Wifi

    当用户单击一个热点后,就会弹出对话框要求输入密码,最后单击“连接”按钮进行连接。具体是在WifiSettings中的submit方法中:

     void submit(WifiConfigController configController) {
    
        final WifiConfiguration config = configController.getConfig();
    
        if (config == null) {
            if (mSelectedAccessPoint != null
                    && mSelectedAccessPoint.isSaved()) {
                connect(mSelectedAccessPoint.getConfig(),
                        true /* isSavedNetwork */,
                        CONNECT_SOURCE_UNSPECIFIED);
            }
        } 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, false /* isSavedNetwork */,
                        CONNECT_SOURCE_UNSPECIFIED);
            }
        }
    
        mWifiTracker.resumeScanning();
    }
    
    
    
    protected void connect(final WifiConfiguration config,
            boolean isSavedNetwork, @ConnectSource int connectSource) {
        // Log subtype if configuration is a saved network.
        mMetricsFeatureProvider.action(getContext(), SettingsEnums.ACTION_WIFI_CONNECT,
                isSavedNetwork);
        mConnectSource = connectSource;
    	// 连接Wifi
        mWifiManager.connect(config, mConnectListener);
        mClickedConnect = true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    点击连接以后,如果config不为null,则先保存网络,再进行连接,所以即使连接失败,此网络依然在已保存网络列表里。

  • 相关阅读:
    go版本升级
    重写 HttpServletRequestWrapper
    小程序WebView远程连接报错(1202)网络出错,轻触屏幕重新加载,如何解决这个问题?
    (附源码)ssm失物招领平台 毕业设计 271621
    MyBatis配置文件(mybatis-config.xml)
    MySQL存储之为什么要使用B+树做为储存结构?
    新书上市|一位家长的忠告:长大后不成才的孩子,父母都忽视了这个点!
    yolov5剪枝实战5:模型剪枝和fine-tune
    【html】H3_表单
    opencv python 深度学习垃圾图像分类系统 计算机竞赛
  • 原文地址:https://blog.csdn.net/jxq1994/article/details/132909718