基于Android 9.0 ATV版 TVSetting源码,研究TVSetting Wifi连接方法
Android TVSetting Wifi连接分析(一)
Android TVSetting Wifi连接分析(二)
Android TVSetting Wifi连接分析(三)
Android TVSetting Wifi连接分析(四)
一、概述
上一章 分析WifiTracker的启动和扫描,从WifiTracker源码上看,WifiTracker 获得了wifi列表(mWifiManager.getScanResults()),并不是直接使用结果,而是采用了相关的缓存以及打分集中应用了打分的机制,来对wifi进行排序,从而在UI显示上以优先级的形式给用户选择。这一章主要分析WifiTracker wifi结果的获取,缓存以及打分应用
二、WIFI结果的获取
OnStart
------fetchScansAndConfigsAndUpdateAccessPoints(mWifiManager.getScanResults();获得当前的扫描结果)
----------updateAccessPoints(将ScanResults转换成AccessPoints)
private void fetchScansAndConfigsAndUpdateAccessPoints() {
//取得扫描结果
final List<ScanResult> newScanResults = mWifiManager.getScanResults();
if (isVerboseLoggingEnabled()) {
Log.i(TAG, "Fetched scan results: " + newScanResults);
}
List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
//进一步处理
updateAccessPoints(newScanResults, configs);
}
获得 ScanResult后,调用 updateAccessPoints进一步处理
updateAccessPoints中首先调用updateScanResultCache来更新ScanResult缓存
/** Update the internal list of access points. */
private void updateAccessPoints(final List<ScanResult> newScanResults,
List<WifiConfiguration> configs) {
..........
//更新updateScanResultCache
ArrayMap<String, List<ScanResult>> scanResultsByApKey =
updateScanResultCache(newScanResults);
..........
}
updateScanResultCache--更新ScanResultCache并返回一个ArrayMap
private ArrayMap<String, List<ScanResult>> updateScanResultCache(
final List<ScanResult> newResults) {
// TODO(sghuman): Delete this and replace it with the Map of Ap Keys to ScanResults for
// memory efficiency
//首先遍历结果,去除SSID为空的wifi
for (ScanResult newResult : newResults) {
if (newResult.SSID == null || newResult.SSID.isEmpty()) {
continue;
}
//mScanResultCache为hash map,SSID作为键值名
mScanResultCache.put(newResult.BSSID, newResult);
}
// Don't evict old results if no new scan results
//wifitrack会设置一个超时时间,如果扫描结果中有热点超时,会被移除
if (!mStaleScanResults) {
evictOldScans();
}
ArrayMap<String, List<ScanResult>> scanResultsByApKey = new ArrayMap<>();
//将mScanResultCache的结果存放到scanResultsByApKey ,提供给外部使用
for (ScanResult result : mScanResultCache.values()) {
// Ignore hidden and ad-hoc networks.
//过滤SSID为空的
if (result.SSID == null || result.SSID.length() == 0 ||
result.capabilities.contains("[IBSS]")) {
continue;
}
//将结果获得AccessPoint Key
//AccessPoint Key 由SSID+Security 组成
//SECURITY_NONE = 0;
//SECURITY_WEP = 1;
// SECURITY_PSK = 2;
//SECURITY_EAP = 3;
String apKey = AccessPoint.getKey(result);
List<ScanResult> resultList;
if (scanResultsByApKey.containsKey(apKey)) {
resultList = scanResultsByApKey.get(apKey);
} else {
resultList = new ArrayList<>();
scanResultsByApKey.put(apKey, resultList);
}
resultList.add(result);
}
return scanResultsByApKey;
}
获得scanResultsByApKey后,进行进一步处理
/** Update the internal list of access points. */
private void updateAccessPoints(final List<ScanResult> newScanResults,
List<WifiConfiguration> configs) {
....
// once for efficiency of lock acquisition time and readability
synchronized (mLock) {
// Swap the current access points into a cached list for maintaining AP listeners
//创建一个AccessPoints List,数据从mInternalAccessPoints拷贝获得
List<AccessPoint> cachedAccessPoints;
cachedAccessPoints = new ArrayList<>(mInternalAccessPoints);
ArrayList<AccessPoint> accessPoints = new ArrayList<>();
final List<NetworkKey> scoresToRequest = new ArrayList<>();
//遍历scanResultsByApKey
for (Map.Entry<String, List<ScanResult>> entry : scanResultsByApKey.entrySet()) {
for (ScanResult result : entry.getValue()) {
//用result 创建NetworkKey
Log.i(TAG, "ScanResult ssid: " + result.SSID);
NetworkKey key = NetworkKey.createFromScanResult(result);
if (key != null && !mRequestedScores.contains(key)) {
//加入打分数组
scoresToRequest.add(key);
}
}
//创建accessPoint或者从Cached中获得一个accessPoint
AccessPoint accessPoint =
getCachedOrCreate(entry.getValue(), cachedAccessPoints);
//更新accessPoint状态
if (mLastInfo != null && mLastNetworkInfo != null) {
accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
}
// Update the matching config if there is one, to populate saved network info
accessPoint.update(configsByKey.get(entry.getKey()));
accessPoints.add(accessPoint);
}
// If there were no scan results, create an AP for the currently connected network (if
// it exists).
// TODO(b/b/73076869): Add support for passpoint (ephemeral) networks
//accessPoints点数组为空处理
if (accessPoints.isEmpty() && connectionConfig != null) {
AccessPoint activeAp = new AccessPoint(mContext, connectionConfig);
activeAp.update(connectionConfig, mLastInfo, mLastNetworkInfo);
accessPoints.add(activeAp);
scoresToRequest.add(NetworkKey.createFromWifiInfo(mLastInfo));
}
//将scoresToRequest 的数据传入,去获得分数?
requestScoresForNetworkKeys(scoresToRequest);
for (AccessPoint ap : accessPoints) {
ap.update(mScoreCache, mNetworkScoringUiEnabled, mMaxSpeedLabelScoreCacheAge);
}
// Pre-sort accessPoints to speed preference insertion
Collections.sort(accessPoints);
mInternalAccessPoints.clear();
//更新mInternalAccessPoints
mInternalAccessPoints.addAll(accessPoints);
}
conditionallyNotifyListeners();
}
三、WIFI打分管理
3.1 涉及类及列表
➢WifiNetworkScoreCache-wifi网络的打分缓存
➢NetworkScoreManager-网络打分管理类
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiNetworkScoreCache.CacheListener;
private WifiNetworkScoreCache mScoreCache;
private final NetworkScoreManager mNetworkScoreManager;
在WifiTracker的构造函数中setWorkThread函数里,完成了mScoreCache的初始化
void setWorkThread(HandlerThread workThread) {
mWorkThread = workThread;
mWorkHandler = new Handler(workThread.getLooper());
//创建mScoreCache 及监听,在抓log时,这里并没有调用
mScoreCache = new WifiNetworkScoreCache(mContext, new CacheListener(mWorkHandler) {
@Override
public void networkCacheUpdated(List<ScoredNetwork> networks) {
if (!mRegistered) return;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Score cache was updated with networks: " + networks);
}
updateNetworkScores();
}
});
}
在onStart中,会调用函数registerScoreCache,实现完成mScoreCache mNetworkScoreManager的绑定。
private void registerScoreCache() {
mNetworkScoreManager.registerNetworkScoreCache(
NetworkKey.TYPE_WIFI,
mScoreCache,
NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS);
}
在updateAccessPoints数组中,会调用 requestScoresForNetworkKeys(scoresToRequest);去请求给wifi打分。
private void requestScoresForNetworkKeys(Collection<NetworkKey> keys) {
if (keys.isEmpty()) return;
if (DBG()) {
Log.d(TAG, "Requesting scores for Network Keys: " + keys);
}
//将NetworkKey传入mNetworkScoreManager,去请求打分
mNetworkScoreManager.requestScores(keys.toArray(new NetworkKey[keys.size()]));
synchronized (mLock) {
//将已经申请过打分的key加入到mRequestedScores队列中,避免重复申请
mRequestedScores.addAll(keys);
}
}
四、总结
这章分析了WIFI结果的获取,及打分的处理过程。下一章分析拿到这个结果后,TVSetting是如何排序及显示的