Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fcd4612f authored by Vinit Deshpande's avatar Vinit Deshpande
Browse files

Fix access point list jumping around in WifiSettings

This happens because the scan times are very aggressive
(to save power); and we don't find all APs on each scan.
So on each scan, some APs are considered lost and some
other are considered found; resulting in reordering the
list.

This change fixes that by requiring 3 scans to confirm
absence of an AP.

Bug: 7263326

Change-Id: I04f61ec5e5aa1589f457645acbf538c7e275a4bf
parent 49e11f80
Loading
Loading
Loading
Loading
+161 −130
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import android.util.LruCache;

import com.android.settingslib.R;

import java.util.ArrayList;
import java.util.Map;


@@ -79,10 +80,15 @@ public class AccessPoint implements Comparable<AccessPoint> {
     *  For now this data is used only with Verbose Logging so as to show the band and number
     *  of BSSIDs on which that network is seen.
     */
    public LruCache<String, ScanResult> mScanResultCache;
    public LruCache<String, ScanResult> mScanResultCache = new LruCache<String, ScanResult>(32);

    private static final String KEY_NETWORKINFO = "key_networkinfo";
    private static final String KEY_WIFIINFO = "key_wifiinfo";
    private static final String KEY_SCANRESULT = "key_scanresult";
    private static final String KEY_SSID = "key_ssid";
    private static final String KEY_SECURITY = "key_security";
    private static final String KEY_PSKTYPE = "key_psktype";
    private static final String KEY_SCANRESULTCACHE = "key_scanresultcache";
    private static final String KEY_CONFIG = "key_config";

    /**
@@ -108,7 +114,6 @@ public class AccessPoint implements Comparable<AccessPoint> {
    private int pskType = PSK_UNKNOWN;

    private WifiConfiguration mConfig;
    private ScanResult mScanResult;

    private int mRssi = Integer.MAX_VALUE;
    private long mSeen = 0;
@@ -125,20 +130,35 @@ public class AccessPoint implements Comparable<AccessPoint> {
        if (mConfig != null) {
            loadConfig(mConfig);
        }
        mScanResult = (ScanResult) savedState.getParcelable(KEY_SCANRESULT);
        if (mScanResult != null) {
            loadResult(mScanResult);
        if (savedState.containsKey(KEY_SSID)) {
            ssid = savedState.getString(KEY_SSID);
        }
        if (savedState.containsKey(KEY_SECURITY)) {
            security = savedState.getInt(KEY_SECURITY);
        }
        if (savedState.containsKey(KEY_PSKTYPE)) {
            pskType = savedState.getInt(KEY_PSKTYPE);
        }
        mInfo = (WifiInfo) savedState.getParcelable(KEY_WIFIINFO);
        if (savedState.containsKey(KEY_NETWORKINFO)) {
            mNetworkInfo = savedState.getParcelable(KEY_NETWORKINFO);
        }
        if (savedState.containsKey(KEY_SCANRESULTCACHE)) {
            ArrayList<ScanResult> scanResultArrayList =
                    savedState.getParcelableArrayList(KEY_SCANRESULTCACHE);
            mScanResultCache.evictAll();
            for (ScanResult result : scanResultArrayList) {
                mScanResultCache.put(result.BSSID, result);
            }
        }
        update(mInfo, mNetworkInfo);
        mRssi = getRssi();
        mSeen = getSeen();
    }

    AccessPoint(Context context, ScanResult result) {
        mContext = context;
        loadResult(result);
        initWithScanResult(result);
    }

    AccessPoint(Context context, WifiConfiguration config) {
@@ -240,6 +260,28 @@ public class AccessPoint implements Comparable<AccessPoint> {
        return WifiManager.calculateSignalLevel(mRssi, 4);
    }

    public int getRssi() {
        int rssi = Integer.MIN_VALUE;
        for (ScanResult result : mScanResultCache.snapshot().values()) {
            if (result.level > rssi) {
                rssi = result.level;
            }
        }

        return rssi;
    }

    public long getSeen() {
        long seen = 0;
        for (ScanResult result : mScanResultCache.snapshot().values()) {
            if (result.timestamp > seen) {
                seen = result.timestamp;
            }
        }

        return seen;
    }

    public NetworkInfo getNetworkInfo() {
        return mNetworkInfo;
    }
@@ -455,7 +497,6 @@ public class AccessPoint implements Comparable<AccessPoint> {
            visibility.append(String.format("rx=%.1f", mInfo.rxSuccessRate));
        }

        if (mScanResultCache != null) {
        int rssi5 = WifiConfiguration.INVALID_RSSI;
        int rssi24 = WifiConfiguration.INVALID_RSSI;
        int num5 = 0;
@@ -559,16 +600,6 @@ public class AccessPoint implements Comparable<AccessPoint> {
        if (numBlackListed > 0)
            visibility.append("!").append(numBlackListed);
        visibility.append("]");
        } else {
            if (mRssi != Integer.MAX_VALUE) {
                visibility.append(" rssi=");
                visibility.append(mRssi);
                if (mScanResult != null) {
                    visibility.append(", f=");
                    visibility.append(mScanResult.frequency);
                }
            }
        }

        return visibility.toString();
    }
@@ -641,22 +672,23 @@ public class AccessPoint implements Comparable<AccessPoint> {
        mConfig = config;
    }

    private void loadResult(ScanResult result) {
    private void initWithScanResult(ScanResult result) {
        ssid = result.SSID;
        security = getSecurity(result);
        if (security == SECURITY_PSK)
            pskType = getPskType(result);
        mRssi = result.level;
        mScanResult = result;
        if (result.seen > mSeen) {
            mSeen = result.seen;
        }
        mSeen = result.timestamp;
    }

    public void saveWifiState(Bundle savedState) {
        savedState.putParcelable(KEY_CONFIG, mConfig);
        savedState.putParcelable(KEY_SCANRESULT, mScanResult);
        if (ssid != null) savedState.putString(KEY_SSID, getSsidStr());
        savedState.putInt(KEY_SECURITY, security);
        savedState.putInt(KEY_PSKTYPE, pskType);
        if (mConfig != null) savedState.putParcelable(KEY_CONFIG, mConfig);
        savedState.putParcelable(KEY_WIFIINFO, mInfo);
        savedState.putParcelableArrayList(KEY_SCANRESULTCACHE,
                new ArrayList<ScanResult>(mScanResultCache.snapshot().values()));
        if (mNetworkInfo != null) {
            savedState.putParcelable(KEY_NETWORKINFO, mNetworkInfo);
        }
@@ -667,32 +699,31 @@ public class AccessPoint implements Comparable<AccessPoint> {
    }

    boolean update(ScanResult result) {
        if (result.seen > mSeen) {
            mSeen = result.seen;
        }
        if (WifiTracker.sVerboseLogging > 0) {
            if (mScanResultCache == null) {
                mScanResultCache = new LruCache<String, ScanResult>(32);
            }
        if (ssid.equals(result.SSID) && security == getSecurity(result)) {
            /* Update the LRU timestamp, if BSSID exists */
            mScanResultCache.get(result.BSSID);

            /* Add or update the scan result for the BSSID */
            mScanResultCache.put(result.BSSID, result);
        }

        if (ssid.equals(result.SSID) && security == getSecurity(result)) {
            if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) {
            int oldLevel = getLevel();
                mRssi = result.level;
                if (getLevel() != oldLevel && mAccessPointListener != null) {
            int oldRssi = getRssi();
            mSeen = getSeen();
            mRssi = (getRssi() + oldRssi)/2;
            int newLevel = getLevel();

            if (newLevel > 0 && newLevel != oldLevel && mAccessPointListener != null) {
                mAccessPointListener.onLevelChanged(this);
            }
            }
            // This flag only comes from scans, is not easily saved in config
            if (security == SECURITY_PSK) {
                pskType = getPskType(result);
            }
            mScanResult = result;

            if (mAccessPointListener != null) {
                mAccessPointListener.onAccessPointChanged(this);
            }

            return true;
        }
        return false;
+60 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

import com.android.internal.annotations.VisibleForTesting;
@@ -35,9 +36,12 @@ import com.android.settingslib.R;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
@@ -45,6 +49,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 */
public class WifiTracker {
    private static final String TAG = "WifiTracker";
    private static final boolean DBG = false;

    /** verbose logging flag. this flag is set thru developer debugging options
     * and used so as to assist with in-the-field WiFi connectivity debugging  */
@@ -70,6 +75,10 @@ public class WifiTracker {
    private boolean mSavedNetworksExist;
    private boolean mRegistered;
    private ArrayList<AccessPoint> mAccessPoints = new ArrayList<>();
    private HashMap<String, Integer> mSeenBssids = new HashMap<>();
    private HashMap<String, ScanResult> mScanResultCache = new HashMap<>();
    private Integer mScanId = 0;
    private static final int NUM_SCANS_TO_CONFIRM_AP_LOSS = 3;

    private NetworkInfo mLastNetworkInfo;
    private WifiInfo mLastInfo;
@@ -166,6 +175,11 @@ public class WifiTracker {
        if (mScanner == null) {
            mScanner = new Scanner();
        }

        mScanResultCache.clear();
        mSeenBssids.clear();
        mScanId = 0;

        if (mWifiManager.isWifiEnabled()) {
            mScanner.resume();
        }
@@ -237,6 +251,33 @@ public class WifiTracker {
        }
    }

    private Collection<ScanResult> fetchScanResults() {
        mScanId++;
        final List<ScanResult> newResults = mWifiManager.getScanResults();
        for (ScanResult newResult : newResults) {
            mScanResultCache.put(newResult.BSSID, newResult);
            mSeenBssids.put(newResult.BSSID, mScanId);
        }

        if (mScanId > NUM_SCANS_TO_CONFIRM_AP_LOSS) {
            if (DBG) Log.d(TAG, "------ Dumping SSIDs that were expired on this scan ------");
            Integer threshold = mScanId - NUM_SCANS_TO_CONFIRM_AP_LOSS;
            for (Iterator<Map.Entry<String, Integer>> it = mSeenBssids.entrySet().iterator();
                    it.hasNext(); /* nothing */) {
                Map.Entry<String, Integer> e = it.next();
                if (e.getValue() < threshold) {
                    ScanResult result = mScanResultCache.get(e.getKey());
                    if (DBG) Log.d(TAG, "Removing " + e.getKey() + ":(" + result.SSID + ")");
                    mScanResultCache.remove(e.getKey());
                    it.remove();
                }
            }
            if (DBG) Log.d(TAG, "---- Done Dumping SSIDs that were expired on this scan ----");
        }

        return mScanResultCache.values();
    }

    private void updateAccessPoints() {
        // Swap the current access points into a cached list.
        List<AccessPoint> cachedAccessPoints = getAccessPoints();
@@ -283,7 +324,7 @@ public class WifiTracker {
            }
        }

        final List<ScanResult> results = mWifiManager.getScanResults();
        final Collection<ScanResult> results = fetchScanResults();
        if (results != null) {
            for (ScanResult result : results) {
                // Ignore hidden and ad-hoc networks.
@@ -328,6 +369,24 @@ public class WifiTracker {

        // Pre-sort accessPoints to speed preference insertion
        Collections.sort(accessPoints);

        // Log accesspoints that were deleted
        if (DBG) Log.d(TAG, "------ Dumping SSIDs that were not seen on this scan ------");
        for (AccessPoint prevAccessPoint : mAccessPoints) {
            if (prevAccessPoint.getSsid() == null) continue;
            String prevSsid = prevAccessPoint.getSsidStr();
            boolean found = false;
            for (AccessPoint newAccessPoint : accessPoints) {
                if (newAccessPoint.getSsid() != null && newAccessPoint.getSsid().equals(prevSsid)) {
                    found = true;
                    break;
                }
            }
            if (!found)
                if (DBG) Log.d(TAG, "Did not find " + prevSsid + " in this scan");
        }
        if (DBG)  Log.d(TAG, "---- Done dumping SSIDs that were not seen on this scan ----");

        mAccessPoints = accessPoints;
        mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
    }