Android11 Wifi enciende, escanea y se conecta

Activar Wi-Fi

Encienda el interruptor Wifi. El interruptor Wifi está WifiEnablerhabilitado WifiEnablerpara SwitchWidgetController.OnSwitchChangeListenermonitoreo. Al encender/apagar el interruptor se volverá a llamar a

// 处理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;
    }

mWifiManager.setWifiEnabled(isChecked)Se utiliza para apagar o encender Wi-Fi según el estado actual del control Switch.

onCheckedChangedSe utiliza una variable al comienzo del método . mStateMachineEventCuando la variable es verdadera, onCheckedChangedel método salta directamente. De hecho, la razón para agregar esta condición de salto es porque el cambio de estado del control del interruptor puede tener las dos situaciones siguientes.

  • Haga clic directamente en el control Switch.

  • Llame al método Switch.setChecked.

Desafortunadamente, las dos situaciones anteriores desencadenan onCheckedChangeduna llamada a un método. No importa qué método cambie el estado del control Switch, onCheckedChangedllamar WifiManager.setWifiEnabledal método para configurar el estado de Wi-Fi activará onCheckedChangedla llamada al método nuevamente. Al onCheckedChangedvolver a llamar al método, debe mStateMachineEventestablecer el valor de la variable en verdadero, de modo que onCheckedChangedel método regrese inmediatamente al comienzo de la ejecución (si continúa ejecutando el siguiente código, provocará un bucle infinito) y luego mStateMachineEventconfigure el valor de la variable a falso. De esta manera, aún podrás continuar ejecutando el método la próxima vez que configures el estado de Wi-Fi onCheckedChanged.

Establecer el estado del control del interruptor usando el método de transmisión

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

Para Wi-Fi, este receptor de transmisión se utiliza principalmente para recibir cambios de estado de Wi-Fi y realizar procesamientos adicionales. El método para manejar los cambios de estado de Wi-Fi es 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;
}

Como se puede ver en setSwitchCheckedel código del método, antes de cambiar el estado del control Switch (llamar Switch.setCheckedal método), mStateMachineEventla variable primero se establece en verdadero. Esto significa que al configurar el estado de control del Switch, onCheckedChangedel estado de Wi-Fi no se volverá a configurar porque el método se activa, por lo que se realiza una llamada recursiva.

A partir de este punto se puede ver que WifiEnablerel propósito del receptor de transmisión en la clase es solo configurar el estado del control Switch, no configurar el estado de Wi-Fi. El propósito de esto es que cuando el usuario WifiManager.setWifiEnabledconfigura el estado de Wi-Fi a través del método, aunque el estado de Wi-Fi se puede configurar correctamente, el estado del control del Switch no se puede cambiar, por lo que el estado actual de Wi-Fi será inconsistente. con el estado del control Switch.Case. Para resolver este problema, WifiManager.setWifiEnableddespués de configurar el estado de Wi-Fi, el método enviará una transmisión ( WifiManager.WIFI_STATE_CHANGED_ACTION), y luego el receptor de transmisión en la clase WifiEnabler recibirá la transmisión y cambiará el estado del control del Switch de acuerdo con la conexión Wi-Fi actual. -Estado de conexión.

Escanear Wi-Fi

WifiSettingsSe activa la lógica para iniciar el escaneo .
WifiTrackerDespués de recibir la transmisión del cambio de estado 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);
            }
        }
    };


Si el wifi ya está activado, comience a escanear 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);
    }

Scanner es una clase utilizada para escanear 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);
    }
}

Primero, la acción de transmisión será procesada por el receptor de transmisión creado en la clase WifiSettings WifiManager.NETWORK_STATE_CHANGED_ACTIONy luego se llamará al método durante el procesamiento Scanner.resumepara comenzar a escanear puntos de acceso. Cuando se completa el escaneo del punto de acceso, el sistema envía WifiManager.SCAN_RESULTS_AVAILABLE_ACTIONuna transmisión.

Llame fetchScansAndConfigsAndUpdateAccessPointsal método para actualizar la lista de puntos de acceso. La actualización específica está en updateAccessPoints(). El objeto aquí envía Scannercontinuamente mensajes retrasados ​​en el método, de modo que el sistema escanea los puntos calientes cada cierto tiempo (10 segundos).Scanner. handleMessage

private void fetchScansAndConfigsAndUpdateAccessPoints() {
		// 获取所有搜索到的热点信息
        List<ScanResult> newScanResults = mWifiManager.getScanResults();

        // Filter all unsupported networks from the scan result list
        final List<ScanResult> filteredScanResults =
                filterScanResultsByCapabilities(newScanResults);

//        if (isVerboseLoggingEnabled()) {
            Log.i(TAG, "Fetched scan results: " + filteredScanResults);
//        }
		// 获取当前已经连接的热点信息
        List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
        updateAccessPoints(filteredScanResults, configs);
    }

updateAccessPoints(filteredScanResults, configs);Se creará el objeto AccessPointer de la información del punto de acceso conectado, se llamará la información del estado de actualización , accessPoint.updatese agregará la información del punto de acceso al punto de acceso y, finalmente, se llamará a la interfaz de usuario de actualización WifiSettingsen la devolución de llamada;onAccessPointsChanged()

Conéctate a Wi-Fi

Cuando el usuario hace clic en un punto de acceso, aparecerá un cuadro de diálogo solicitando una contraseña y finalmente hace clic en el botón "Conectar" para conectarse. Específicamente en el WifiSettingsmétodo 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;
}

Después de hacer clic en Conectar, si la configuración no es nula, la red se guardará primero y luego se conectará, por lo que incluso si la conexión falla, la red seguirá estando en la lista de redes guardadas.

Supongo que te gusta

Origin blog.csdn.net/jxq1994/article/details/132909718
Recomendado
Clasificación