BUG需求描述:
提示:这里简述项目相关背景:
Android13中客户需求添加WIFI频段选项:
2.4G only,只显示链接2.4G的AP。
5G only,只能显示和链接5G的AP。
Automatic:自动显示,即全部正常显示。
解决初衷
提示:这里描述项目中遇到的问题:
作为初学者的我,刚开始接到这个bug,还是比较懵的,多亏了CSDN的前辈发表的文章给予我很大的帮助。站在巨人的肩膀上看的更远,我在前辈的文章上进一步添加自己的理解,剖析其中的逻辑,希望能给大家提供帮助!
你需要具备有关WIFI的一点小知识
1.android wifi scanresult.接口
ScanResult类实现Parcelable接口:ScanResult类描述了一个已发现AP的信息。除了在该类中描述的属性,supplicant还跟踪了quality(品质),noise(噪声),maxbitrate(最大比特率)属性,但是并不立刻将它们通知给客户端。
2.1.目录位置:
/frameworks/base/wifi/java/android/net/wifi/
3.WIFI频段中24G和5G核心方法
1.public boolean is24GHz():直接调用is24GHz(frequency),即用自己的信道频率值进行判断,如果频率值在2400~2500之间,(不包括2400和2500两个边界值),则返回true,否则返回false。
2.public boolean is5GHz(int freq):用传入的freq值进行判断,若在4900~5900之间,不含边界,则返回true,否则返回false。
更改后的样式展示
实现思路
设置页面里使用ListPreference静态增加"WLAN频段"菜单项,通过选项将设定的wifi频段值保存在settings数据库中,最后在WifiManager里处理其中的逻辑。
代码实现步骤(保姆式教学):
1.首先第一步骤需要在相应的布局位置添加相应的布局。
system/vendor/mediatek/proprietary/packages/apps/MtkSettings/res/xml/wifi_configure_settings.xml
资源文件需在strings.xml中单独配置
<ListPreference
android:key="wifi_frequency_options"
android:title="@string/wifi_frequency_options_title"//需要自己去string.xml中定义
android:summary="@string/wifi_frequency_options_summary"//需要自己去string.xml中定义
android:negativeButtonText="@android:string/cancel"
android:persistent="false"
android:entries="@array/wifi_frequency_options_entries"
android:entryValues="@array/wifi_frequency_options_values"
settings:controller="com.android.settings.wifi.WifiFrequencyBandPreferenceController"/>
布局页面位置
2.vendor/mediatek/proprietary/packages/apps/MtkSettings/res/values/arrays.xml
添加相应的数组和添加相应的选项
<string-array name="wifi_frequency_options_entries">
<item>Automatic</item>
<item>2.4 GHz only</item>
<item>5 GHz only</item>
</string-array>
<string-array name="wifi_frequency_options_values">
<item>2</item>
<item>1</item>
<item>0</item>
</string-array>
参考文章添加位置
3.新增控制文件
system/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/wifi/WifiFrequencyBandPreferenceController.java
package com.android.settings.wifi;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.provider.Settings;
import android.util.Log;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.xchengtech.ProjectConfig;
public class WifiFrequencyBandPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
private static Context mContext;
private WifiManager mWifiManager;
public String getPreferenceKey() {
return "wifi_frequency_options";
}
public boolean isAvailable() {
return true; //可以设置相应宏控判定该模块是否呈现
}
public WifiFrequencyBandPreferenceController(Context context, Lifecycle lifecycle, WifiManager wifiManager) {
super(context);
mContext = context;
this.mWifiManager = wifiManager;
}
public void displayPreference(PreferenceScreen preferenceScreen) {
super.displayPreference(preferenceScreen);
ListPreference listPreference = (ListPreference) preferenceScreen.findPreference("wifi_frequency_options");
int frequencyBand = getFrequencyBand();
listPreference.setValue("" + frequencyBand);
updateFrequencyBandSummary(listPreference, "" + frequencyBand);
}
public boolean onPreferenceChange(Preference preference, Object obj) {
String str = (String) obj;
int parseInt = Integer.parseInt(str);
updateFrequencyBandSummary((ListPreference) preference, str);
boolean b = Settings.Global.putInt(mContext.getContentResolver(), "wifi_frequency_band", parseInt);
if (b) {
if (null != mWifiManager) {
if (mWifiManager.isWifiEnabled()) {
mWifiManager.setWifiEnabled(false);
mWifiManager.setWifiEnabled(true);
}else{
mWifiManager.setWifiEnabled(true);
mWifiManager.setWifiEnabled(false);
}
}
}
return true;
}
private int getFrequencyBand() {
return Settings.Global.getInt(mContext.getContentResolver(), "wifi_frequency_band", 2);
}
private void updateFrequencyBandSummary(ListPreference listPreference, String str) {
listPreference.setSummary(listPreference.getEntries()[listPreference.findIndexOfValue(str)]);
}
}
4.在WIFI设置项中的控制类添加相应的控制模块
system/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/wifi/ConfigureWifiSettings.java
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
final WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new WifiP2pPreferenceController(context, getSettingsLifecycle(),
wifiManager));
/// M: For wapi cert manager feature @{
controllers.add(new WapiCertPreferenceController(context));
/// @}
//add by wjj for wifi frequency options start
controllers.add(new WifiFrequencyBandPreferenceController(context, getSettingsLifecycle(), wifiManager));
//add by wjj for wifi frequency options end
return controllers;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
5.核心逻辑实现类在wifimanager.java类中的getScanResults()方法中
首先现在最上方设置相应的宏定义
system/packages/modules/Wifi/framework/java/android/net/wifi/WifiManager.java
//wjj add
final int wifi_band_5_ghz = 0;
final int wifi_band_24_ghz = 1;
final int wifi_band_5_24ghz = 2;
//wjj end
再在相应的方法中添加相应的判断逻辑
/**
* Return the results of the latest access point scan.
* @return the list of access points found in the most recent scan. An app must hold
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
* and {@link android.Manifest.permission#ACCESS_WIFI_STATE} permission
* in order to get valid results.
*/
@RequiresPermission(allOf = {ACCESS_WIFI_STATE, ACCESS_FINE_LOCATION})
public List<ScanResult> getScanResults() {
try {
//add by wjj for wifi frequency options start
if (true) { //此处可以进一步设置判断
List<ScanResult> results = mService.getScanResults(mContext.getOpPackageName(),mContext.getAttributionTag()); //设置scanResult类型的列表 result 获取每一条wifi字段包含许多属性
int wifiFrequency = Settings.Global.getInt(mContext.getContentResolver(), "wifi_frequency_band", 2); //wifiFrequency 只获取其中的频段
if(results != null && results.size() > 0){//判空逻辑,列表不为空则进行下一步
WifiInfo wifiInfo = getConnectionInfo();//获取所有可以链接的项(我的理解)
Iterator<ScanResult> iterator = results.iterator();//迭代器进行遍历
while (iterator.hasNext()) {//迭代器结果判断
ScanResult result = iterator.next();
if(ScanResult.is24GHz(result.frequency) && (wifiFrequency == wifi_band_5_ghz)){//异常值即频段只有2.4G但band等级达到5G的异常值(不是很懂怎么表述,希望大佬指正)意思大概就是异常值移除
iterator.remove();//移除操作
if (ScanResult.is24GHz(wifiInfo.getFrequency())) {//符合2.4G
disableEphemeralNetwork(wifiInfo.getSSID());//隐藏相应的显示信息
disconnect();//断开链接
}
}
if((ScanResult.is5GHz(result.frequency) || result.frequency >= 5900 )
&& (wifiFrequency == wifi_band_24_ghz)){//符合5G频段或6G但wifi等级却是2.4G的异常值移除
iterator.remove();
if (ScanResult.is5GHz(wifiInfo.getFrequency()) || result.frequency >= 5900) {//符合5G或以上条件的
disableEphemeralNetwork(wifiInfo.getSSID());//隐藏
disconnect();//断开链接
}
}
}
}
return results;
} else {//扫描结果全部进行显示
return mService.getScanResults(mContext.getOpPackageName(),
mContext.getAttributionTag());
}
//add by wjj for wifi frequency options end
} catch (RemoteException e) {//异常处理
throw e.rethrowFromSystemServer();
}
}
Bug优化1:解决wifi频率切换时,有时不会自动断开或重新连接
1.system/packages/modules/Wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
/**
* Handles 'onResult' callbacks for the Periodic, Single & Pno ScanListener.
* Executes selection of potential network candidates, initiation of connection attempt to that
* network.
*/
private void handleScanResults(@NonNull List<ScanDetail> scanDetails,
@NonNull String listenerName,
boolean isFullScan,
@NonNull HandleScanResultsListener handleScanResultsListener) {
//add by wjj for wifi frequency options start
Iterator<ScanDetail> iterator = scanDetails.iterator();
int wifi_frequency_band = Settings.Global.getInt(mContext.getContentResolver(), "wifi_frequency_band", 2);
while (iterator.hasNext()) {
ScanDetail result = iterator.next();
ScanResult sr = result.getScanResult();
if ((!ScanResult.is24GHz(sr.frequency) && (wifi_frequency_band == wifi_band_24_ghz))
|| (!ScanResult.is5GHz(sr.frequency) && wifi_frequency_band == wifi_band_5_ghz)) {
iterator.remove();
}
}
//add by wjj for wifi frequency options end
List<WifiNetworkSelector.ClientModeManagerState> cmmStates = new ArrayList<>();
Set<String> connectedSsids = new HashSet<>();
boolean hasExistingSecondaryCmm = false;
for (ClientModeManager clientModeManager :
mActiveModeWarden.getInternetConnectivityClientModeManagers()) {
if (clientModeManager.getRole() == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
hasExistingSecondaryCmm = true;
}
mWifiChannelUtilization.refreshChannelStatsAndChannelUtilization(
clientModeManager.getWifiLinkLayerStats(),
WifiChannelUtilization.UNKNOWN_FREQ);
WifiInfo wifiInfo = clientModeManager.syncRequestConnectionInfo();
if (clientModeManager.isConnected()) {
connectedSsids.add(wifiInfo.getSSID());
}
cmmStates.add(new WifiNetworkSelector.ClientModeManagerState(clientModeManager));
}
// We don't have any existing secondary CMM, but are we allowed to create a secondary CMM
// and do we have a request for OEM_PAID/OEM_PRIVATE request? If yes, we need to perform
// network selection to check if we have any potential candidate for the secondary CMM
// creation.
if (!hasExistingSecondaryCmm
&& (mOemPaidConnectionAllowed || mOemPrivateConnectionAllowed)) {
// prefer OEM PAID requestor if it exists.
WorkSource oemPaidOrOemPrivateRequestorWs =
mOemPaidConnectionRequestorWs != null
? mOemPaidConnectionRequestorWs
: mOemPrivateConnectionRequestorWs;
if (oemPaidOrOemPrivateRequestorWs == null) {
Log.e(TAG, "Both mOemPaidConnectionRequestorWs & mOemPrivateConnectionRequestorWs "
+ "are null!");
}
if (oemPaidOrOemPrivateRequestorWs != null
&& mActiveModeWarden.canRequestMoreClientModeManagersInRole(
oemPaidOrOemPrivateRequestorWs,
ROLE_CLIENT_SECONDARY_LONG_LIVED, false)) {
// Add a placeholder CMM state to ensure network selection is performed for a
// potential second STA creation.
cmmStates.add(new WifiNetworkSelector.ClientModeManagerState());
hasExistingSecondaryCmm = true;
}
}
2.自己添加的控制类中完善
system/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/wifi/WifiFrequencyBandPreferenceController.java
public boolean onPreferenceChange(Preference preference, Object obj) {
String str = (String) obj;
int parseInt = Integer.parseInt(str);
updateFrequencyBandSummary((ListPreference) preference, str);
boolean b = Settings.Global.putInt(mContext.getContentResolver(), "wifi_frequency_band", parseInt);
if (b) {
if (null != mWifiManager) {
if (mWifiManager.isWifiEnabled()) {
mWifiManager.setWifiEnabled(false);
mWifiManager.setWifiEnabled(true);
//add by wjj for wifi frequency options start
mWifiManager.startScan();
//add by wjj for wifi frequency options end
}else{
mWifiManager.setWifiEnabled(true);
mWifiManager.setWifiEnabled(false);
}
}
}
return true;
}
Bug优化2:这个是前辈优化步骤值得借鉴
对于双频合一的wifi优化:android13中如果未对双频wifi优化,当选择2.4g频段时,连接双频合一wifi,此wifi不是2.4g频率(还是5g频率),正常现象应该是连上双频合一wifi2.4g频率的。
public boolean startSingleScan(WifiNative.ScanSettings settings,
WifiNative.ScanEventHandler eventHandler) {
if (eventHandler == null || settings == null) {
Log.w(TAG, "Invalid arguments for startSingleScan: settings=" + settings
+ ",eventHandler=" + eventHandler);
return false;
}
synchronized (mSettingsLock) {
if (mLastScanSettings != null) {
Log.w(TAG, "A single scan is already running");
return false;
}
ChannelCollection allFreqs = mChannelHelper.createChannelCollection();
boolean reportFullResults = false;
for (int i = 0; i < settings.num_buckets; ++i) {
WifiNative.BucketSettings bucketSettings = settings.buckets[i];
if ((bucketSettings.report_events
& WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
reportFullResults = true;
}
allFreqs.addChannels(bucketSettings);
}
List<String> hiddenNetworkSSIDSet = new ArrayList<>();
if (settings.hiddenNetworks != null) {
boolean executeRoundRobin = true;
int maxNumScanSsids = mMaxNumScanSsids;
if (maxNumScanSsids <= 0) {
// Subtract 1 to account for the wildcard/broadcast probe request that
// wificond adds to the scan set.
mMaxNumScanSsids = mWifiNative.getMaxSsidsPerScan(getIfaceName()) - 1;
if (mMaxNumScanSsids > 0) {
maxNumScanSsids = mMaxNumScanSsids;
} else {
maxNumScanSsids = DEFAULT_NUM_HIDDEN_NETWORK_IDS_PER_SCAN;
executeRoundRobin = false;
}
}
int numHiddenNetworksPerScan =
Math.min(settings.hiddenNetworks.length, maxNumScanSsids);
if (numHiddenNetworksPerScan == settings.hiddenNetworks.length
|| mNextHiddenNetworkScanId >= settings.hiddenNetworks.length
|| !executeRoundRobin) {
mNextHiddenNetworkScanId = 0;
}
if (DBG) {
Log.d(TAG, "Scanning for " + numHiddenNetworksPerScan + " out of "
+ settings.hiddenNetworks.length + " total hidden networks");
Log.d(TAG, "Scan hidden networks starting at id=" + mNextHiddenNetworkScanId);
}
int id = mNextHiddenNetworkScanId;
for (int i = 0; i < numHiddenNetworksPerScan; i++, id++) {
hiddenNetworkSSIDSet.add(
settings.hiddenNetworks[id % settings.hiddenNetworks.length].ssid);
}
mNextHiddenNetworkScanId = id % settings.hiddenNetworks.length;
}
mLastScanSettings = new LastScanSettings(
mClock.getElapsedSinceBootNanos(),
reportFullResults, allFreqs, eventHandler);
boolean success = false;
Set<Integer> freqs = Collections.emptySet();
//add by ysliu 2023.9.28 start
//Set<Integer> freqs;
final int wifi_band_5_ghz = 0;
final int wifi_band_24_ghz = 1;
final int wifi_band_5_24ghz = 2;
int[] channels = null;
int[] channelDfs = null;
int frequencyBand = Settings.Global.getInt(mContext.getContentResolver(), "wifi_frequency_band", 2);
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);
//add by ysliu 2023.9.28 end
if (!allFreqs.isEmpty()) {
// freqs = allFreqs.getScanFreqs(); //modify by ysliu 2023.9.28
success = mWifiNative.scan(
getIfaceName(), settings.scanType, freqs, hiddenNetworkSSIDSet,
settings.enable6GhzRnr);
if (!success) {
Log.e(TAG, "Failed to start scan, freqs=" + freqs);
}
} else {
// There is a scan request but no available channels could be scanned for.
// We regard it as a scan failure in this case.
Log.e(TAG, "Failed to start scan because there is no available channel to scan");
}
if (success) {
if (DBG) {
Log.d(TAG, "Starting wifi scan for freqs=" + freqs
+ " on iface " + getIfaceName());
}
mScanTimeoutListener = new AlarmManager.OnAlarmListener() {
@Override
public void onAlarm() {
handleScanTimeout();
}
};
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,
TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);
} else {
// indicate scan failure async
mEventHandler.post(() -> reportScanFailure());
}
}
return true;
}
}
总结:
1.Android 10 或更高版本为目标平台的应用调用WifiManager相关api(setWifiEnable、startScan、getScanResults等方法)不会生效,会返回false
2.调用Wi-Fi信息需要以下权限
添加位置在settings的菜单文件中(一般都有加)
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
最后的总结:
伙伴们,我是参考一位叫ysliu的前辈的,在他的基础上进行进一步的补充,作为刚入职场的人来说,太需要这样板书十分仔细的前辈了,如果您看到这里啦,可以再去看看前辈写的东西,真的很详细 前辈的CSDN。希望我记录的这些东西能够帮助到更多的人吧!–一位初入职场大学学大数据的android开发从业者。
前辈更多优秀文章的链接(上方超链接也可以哈):文章来源:https://www.toymoban.com/news/detail-753069.html
Lysssx前辈文章来源地址https://www.toymoban.com/news/detail-753069.html
到了这里,关于【Android13开发WIFI添加频段设置项(2.4G/5G/automatic)更改笔记】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!