开启Wifi
开启Wifi开关,Wifi开关是WifiEnabler
,WifiEnabler
实现了 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;
}
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());
}
}
};
对于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;
}
从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);
}
}
};
如果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);
}
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);
}
}
首先会由WifiSettings类中创建的广播接收器处理WifiManager.NETWORK_STATE_CHANGED_ACTION
广播动作,然后在处理的过程中调用了Scanner.resume
方法开始扫描热点。当热点扫描完成后,系统发送 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION
广播。
调用fetchScansAndConfigsAndUpdateAccessPoints
方法更新热点列表,具体更新是在updateAccessPoints()
。这里的Scanner
对象通过不断在Scanner. handleMessage
方法中发送延迟消息,从而使系统每隔一定时间(10秒)就会扫描一次热点。
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);
中会创建已经连接的热点信息的AccessPointer对象,调用accessPoint.update
更新状态信息,将热点信息添加到热点,最后回调WifiSettings
中的onAccessPointsChanged()
更新UI;
连接Wifi
当用户单击一个热点后,就会弹出对话框要求输入密码,最后单击“连接”按钮进行连接。具体是在WifiSettings
中的submit
方法中:文章来源:https://www.toymoban.com/news/detail-733546.html
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;
}
点击连接以后,如果config不为null,则先保存网络,再进行连接,所以即使连接失败,此网络依然在已保存网络列表里。文章来源地址https://www.toymoban.com/news/detail-733546.html
到了这里,关于Android11 Wifi开启、扫描和连接的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!