Android AccessPoint 已连接的wifi信息未显示处理

Android AccessPoint 已连接的wifi信息未显示处理

一、前言

一个wifi列表未显示已连接的wifi信息问题记录。

虽然新版本的原生Settings应用基本不会遇到这个问题,但是万一遇到可以参考这个简单适配。

背景:很久以前的项目代码,移植的Settings的代码,代码获取的wifi列表信息是使用SettingsLib的接口获取 AccessPoint 列表数据。
目前只有wifi5的模组硬件会遇到这个问题,wifi6模组的硬件没有这个问题。
有可能是底层返回的某个信息不符合正常逻辑,所以才出现这样的问题。

本文只是简单记录一下,估计对大部分开发人员是没啥用的。

本文最后又原生Settings 的Wifi列表界面显示分析,有兴趣的可以看看。

二、简单分析和处理

1、系统应用中获取Wifi列表的代码

WifiTracker mWifiTracker = WifiTrackerFactory.create(
                getActivity(), this, getLifecycle(), true, true);
List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();

无论是 WifiTracker 还是 AccessPoint 都是已经过时的API。
但是系统代码中还是可以正常使用。


    /** Update the internal list of access points. */
    private void updateAccessPoints(final List<ScanResult> newScanResults,
            List<WifiConfiguration> configs) {

        WifiConfiguration connectionConfig = null;
        if (mLastInfo != null) {
            connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId(), configs);
        }

+        boolean isHasConnectWifi = false;

            List<ScanResult> cachedScanResults = new ArrayList<>(mScanResultCache.values());

            // Add a unique Passpoint AccessPoint for each Passpoint profile's unique identifier.
            accessPoints.addAll(updatePasspointAccessPoints(
                    mWifiManager.getAllMatchingWifiConfigs(cachedScanResults), cachedAccessPoints));

            // Add OSU Provider AccessPoints
            accessPoints.addAll(updateOsuAccessPoints(
                    mWifiManager.getMatchingOsuProviders(cachedScanResults), cachedAccessPoints));

            if (mLastInfo != null && mLastNetworkInfo != null) {
                for (AccessPoint ap : accessPoints) {
                    ap.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                }
            }

+            //add judge connected wifi by lwz
+            String ssid = "";
+            int networkId = -1;
+            if (mLastInfo != null) { //上次连接成功的wifi信息对象
+                ssid = mLastInfo.getSSID();
+                networkId = mLastInfo.getNetworkId();
+                Log.i(TAG, "updateAccessPoints last ssid = " + ssid + " , networkId = " + networkId);
+            }
+            isHasConnectWifi = false;
+            for (AccessPoint as : accessPoints) {
+                if (removeDoubleQuotes(ssid).equals(removeDoubleQuotes(as.getSsidStr())) && 
+                    as.getConfig() != null && networkId == +as.getConfig().networkId) {
+                    isHasConnectWifi = true;
+                }
+
+            }
+
+           if (!isHasConnectWifi) {
+               Log.i(TAG, "updateAccessPoints isHasConnectWifi = +" + isHasConnectWifi + ", connectionConfig = " + connectionConfig);
+           }

            // If there were no scan results, create an AP for the currently connected network (if
            // it exists).
-            if (accessPoints.isEmpty() && connectionConfig != null) {
+            if (connectionConfig != null && (accessPoints.isEmpty() || !isHasConnectWifi)) {
                AccessPoint activeAp = new AccessPoint(mContext, connectionConfig);
                activeAp.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                accessPoints.add(activeAp);
            }


    }


+    //remove shuanyinhao ""
+    private String removeDoubleQuotes(String var0) {
+        if (TextUtils.isEmpty(var0)) {
+            return "";
+        } else {
+            int var1 = var0.length();
+            return var1 > 1 && var0.charAt(0) == '"' && var0.charAt(var1 - 1) == '"' ? var0.substring(1, var1 - 1) : var0;
+        }
+    }


这里可以看到代码中有保存上次连接的wifi信息。
如果返回的 AccessPoint 列表中未返回这个信息就添加这个信息。

三、其他

1、Android AccessPoint 已连接的wifi信息未显示处理小结

本文没有深入研究为啥已连接的Wifi信息未显示的具体原因,
只介绍了一个解决方案:修改 updateAccessPoints 的列表数据;
如果要深入分析可以在 updateAccessPoints 的多个判断出来添加打印,查看是哪里过滤了这个Wifi信息。

这个问题并不容易出现,是某些定制板子会出现,并且是连接隐藏的Wifi才会有这个问题,
后续没有硬件研究了,就不管了。

2、Android14 原生Settings 的Wifi列表界面分析

(1)AndroidManifest.xml 中代码
       <activity
            android:name="Settings$WifiSettingsActivity"
            android:exported="true"
            android:configChanges="orientation|keyboardHidden|screenSize">
            <intent-filter android:priority="1">
                <action android:name="android.settings.WIFI_SETTINGS"/>
            </intent-filter>
            // wifi 列表具体显示的Fragment:NetworkProviderSettings
           <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                       android:value="com.android.settings.network.NetworkProviderSettings"/>
            ...
        </activity>

Settings代码中是没有 WifiSettingsActivity.java 的;
WifiSettingsActivity 只是Settings.java 的内部类。

(2)Settings.java

Settings\src\com\android\settings\Settings.java

public class Settings extends SettingsActivity {

    public static class WifiSettingsActivity extends SettingsActivity { /* empty */ }
    
    public static class NetworkProviderSettingsActivity extends SettingsActivity { /* empty */ }
    public static class NetworkSelectActivity extends SettingsActivity { /* empty */ }
。。。
}

SettingsActivity.java 确实是存在的,是一个通用的Activity类。

(2) adb shell或者串口拉起Wifi设置界面的命令1:
am start -a android.settings.WIFI_SETTINGS 
//$号必须转义,否则无效!
am start -n com.android.settings/.Settings\$WifiSettingsActivity  
(3)从全局搜索 WifiSettings 看,还有其他Java类也是跳转到Wifi列表界面的

比如:WifiPickerActivity.java

public class WifiPickerActivity extends SettingsActivity implements ButtonBarHandler {

    //这里可以看到最对某些Intent进行过滤和设置
    @Override
    public Intent getIntent() {
        Intent modIntent = new Intent(super.getIntent());
        if (!modIntent.hasExtra(EXTRA_SHOW_FRAGMENT)) {
            modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getWifiSettingsClass().getName());
            modIntent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.wifi_select_network);
        }
        return modIntent;
    }
...

    /* package */ Class<? extends PreferenceFragmentCompat> getWifiSettingsClass() {
        return WifiSettings.class;
    }
}

AndroidManifest.xml 中定义WifiPickerActivity的代码

<activity
    android:name=".wifi.WifiPickerActivity"
    android:permission="android.permission.CHANGE_WIFI_STATE"
    android:exported="true">
    <intent-filter android:priority="1">
        <action android:name="android.net.wifi.PICK_WIFI_NETWORK" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
        android:value="true" />
</activity>
            

这里只是简单找的其中一个,估计还有一些类也是会跳转到Wifi列表设置界面的。

(4)adb shell或者串口拉起Wifi设置界面的命令2:
am start -n com.android.settings/.wifi.WifiPickerActivity
am start -a android.net.wifi.PICK_WIFI_NETWORK

但是代码中没有看到实现的地方???

(5)NetworkProviderSettings.java

具体实现是在 NetworkProviderSettings.java ,一个Fragment 界面中。

下面是部分代码:

/**
 * UI for Mobile network and Wi-Fi network settings.
 *
 * TODO(b/167474581): Define the intent android.settings.NETWORK_PROVIDER_SETTINGS in Settings.java.
 */
@SearchIndexable
public class NetworkProviderSettings extends RestrictedSettingsFragment ... {
      private static final String TAG = "NetworkProviderSettings";

    //已连接的Wifi条目
    static final String PREF_KEY_CONNECTED_ACCESS_POINTS = "connected_access_point";

    //保存的Wifi条目
    static final String PREF_KEY_FIRST_ACCESS_POINTS = "first_access_points";
    //剩余的Wifi列表
    private static final String PREF_KEY_ACCESS_POINTS = "access_points";
    
    //Wifi偏好设置条目
    private static final String PREF_KEY_CONFIGURE_NETWORK_SETTINGS = "configure_network_settings";

    //每个条目的 Preference 对象
    PreferenceCategory mConnectedWifiEntryPreferenceCategory;
    @VisibleForTesting
    PreferenceCategory mFirstWifiEntryPreferenceCategory;
    @VisibleForTesting
    PreferenceCategory mWifiEntryPreferenceCategory;

    //Preference 对象绑定,初始化
    private void addPreferences() {
        addPreferencesFromResource(R.xml.network_provider_settings);

        mConnectedWifiEntryPreferenceCategory = findPreference(PREF_KEY_CONNECTED_ACCESS_POINTS);
        mFirstWifiEntryPreferenceCategory = findPreference(PREF_KEY_FIRST_ACCESS_POINTS);
        //wifi 列表
        mWifiEntryPreferenceCategory = findPreference(PREF_KEY_ACCESS_POINTS);
        mConfigureWifiSettingsPreference = findPreference(PREF_KEY_CONFIGURE_NETWORK_SETTINGS);
    }


    //Wifi列表更新主要代码:
    protected void updateWifiEntryPreferences() {
    ...
    List<WifiEntry> wifiEntries = mWifiPickerTracker.getWifiEntries();
    for (WifiEntry wifiEntry : wifiEntries) {
            hasAvailableWifiEntries = true;

            String key = wifiEntry.getKey();
            LongPressWifiEntryPreference pref =
                    (LongPressWifiEntryPreference) getCachedPreference(key);
         ...
            //wifi 列表
            mWifiEntryPreferenceCategory.addPreference(pref);
        }
    }
}

不同的Android版本上的Settings实现是有差异的;
特别是Android9前后Settings实现逻辑变化很大。

Android9 或者更低的版本使用的是:
List accessPoints = mWifiTracker.getAccessPoints();

Android11 或者更新的版本获取Wifi使用的是:
List wifiEntries = mWifiPickerTracker.getWifiEntries();

因为 AccessPoint 过时了,所以使用的是 WifiEntry;
AccessPoint 是系统SettingsLib包封装的对象,WifiEntry 是系统framework包的对象;

WifiTracker 对象是SettingsLib的一个封装类,扫描和获取Wifi列表都是里面实现的;
所以在Settings全局搜索是无法查看到普通扫描和接收Wifi信息的代码的;

普通应用扫描和获取Wifi列表的代码:

WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
//Wifi扫描
wifiManager.startScan();

// 获取扫描结果,一般是接收WifiManager.SCAN_RESULTS_AVAILABLE_ACTION 后获取
wifiScanResults = wifiManager.getScanResults();

原生Settings是搜索不到上面这些代码的;大部分Wifi具体操作都是使用的SettingsLib的封装方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

峥嵘life

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值