最近遇到一个新需求,成品如下,就是WiFi扫描界面增加一个选项,可以只扫描2.4G或者5G的AP。
方案一
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ScanRequestProxy.java 从代码里可以看到WiFi扫描默认是全扫描的,不会对 2.4G 和 5G 做筛选。
代码语言:javascript复制public boolean startScan(int callingUid, String packageName) {
.............
// always do full scans
settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
.............
}
下面是我的修改,frequencyBand 是写入数据库的标志位,UI 界面选择了以后改变这个数据,然后这里读取,再做相应的操作。关于Settings数据库的使用可以看 Settings数据库的使用 。
代码语言:javascript复制private static final String Ap_Frequency_Band = "ap_frequency_band";
public static final int WIFI_BAND_24_GHZ = 1;
public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6;
public static final int WIFI_BAND_BOTH_WITH_DFS = 7;
public boolean startScan(int callingUid, String packageName) {
.............
int frequencyBand = Settings.Global.getInt(mContext.getContentResolver(), Ap_Frequency_Band, 0);
switch (frequencyBand) {
case WIFI_BAND_24_GHZ:
settings.band = WifiScanner.WIFI_BAND_24_GHZ;
break;
case WIFI_BAND_5_GHZ_WITH_DFS:
settings.band = WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS;
break;
case WIFI_BAND_BOTH_WITH_DFS:
settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
break;
default:
settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
break;
}
//settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
.............
}
这么做有一个弊端就是底层依然会扫描,但是上传到 framework 会根据 ScannerSettings 做筛选。这样的话如果你之前连过一个2.4G的AP,现在选择只扫描5G的AP,手机还是会自动重连到你之前保存过的那个2.4GAP,因为底层已经扫描到了。
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java 下面是我在连接网络时做的处理,在连接AP时判断用户选择的频率扫描选项,如果用户选了5G,则连接网络时如果是2.4G的AP则直接返回空,不连接。这样就解决了上面的问题。
代码语言:javascript复制private void connectToNetwork(WifiConfiguration candidate) {
ScanResult scanResultCandidate = candidate.getNetworkSelectionStatus().getCandidate();
if (scanResultCandidate == null) {
localLog("connectToNetwork: bad candidate - " candidate
" scanResult: " scanResultCandidate);
return;
}
添加的代码:
frequencyBand = Settings.Global.getInt(mContext.getContentResolver(), Ap_Frequency_Band, 7);
if (!((frequencyBand == WIFI_BAND_24_GHZ && scanResultCandidate.is24GHz())
|| (frequencyBand == WIFI_BAND_5_GHZ_WITH_DFS && scanResultCandidate.is5GHz())
|| (frequencyBand == WIFI_BAND_BOTH_WITH_DFS))) {
return;
}
}
方案二
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
后来就想能不能让底层扫描的时候就只扫描某个band的AP呢?结果找到了扫描时 framework 传给底层的参数中就有 freqs 参数,那我修改这个参数不就好了。一看代码果然是不区分,直接全扫描,如何就是修改,和UI通信的方式还是Settings数据库,上面说过了,这里不赘述。
原代码:
代码语言:javascript复制public boolean startSingleScan(WifiNative.ScanSettings settings,
WifiNative.ScanEventHandler eventHandler) {
synchronized (mSettingsLock) {
boolean success = false;
Set<Integer> freqs;
if (!allFreqs.isEmpty()) {
freqs = allFreqs.getScanFreqs();
success = mWifiNative.scan(
mIfaceName, settings.scanType, freqs, hiddenNetworkSSIDSet);
if (!success) {
Log.e(TAG, "Failed to start scan, freqs=" freqs);
}
} else {
}
channels 是有函数去获取2.4G或者5G对应的频率的,我们把这个写入 freq 就可以。
修改的代码:
代码语言:javascript复制public boolean startSingleScan(WifiNative.ScanSettings settings,
WifiNative.ScanEventHandler eventHandler) {
synchronized (mSettingsLock) {
boolean success = false;
修改的代码:
//Set<Integer> freqs;
int[] channels = null;
int[] channelDfs = null;
int frequencyBand = Settings.Global.getInt(mContext.getContentResolver(), Ap_Frequency_Band, 7);
Log.d(TAG, "Ap_Frequency_Band = " frequencyBand);
if (!allFreqs.isEmpty()) {
//freqs = allFreqs.getScanFreqs();
ArraySet<Integer> mChannels = new ArraySet<Integer>();
switch (frequencyBand) {
case WIFI_BAND_24_GHZ:
channels = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ);
break;
case WIFI_BAND_5_GHZ:
channels = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ);
channelDfs = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY);
break;
default:
break;
}
if (null != channels){
for (int chan : channels) {
mChannels.add(chan);
}
if (null != channelDfs){
for (int chan : channelDfs) {
mChannels.add(chan);
}
}
freqs= new ArraySet<Integer>(mChannels);
} else {
freqs = allFreqs.getScanFreqs();
}
Log.d(TAG, "freqs=" freqs);