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

Commit 5519b7b8 authored by Sundeep Ghuman's avatar Sundeep Ghuman
Browse files

Add rankingScores and badges to WifiPicker.

Adds support to request scores in WifiTracker and then plumb
those scores via AccessPoint.java. AccessPoints will sort on
ranking scores. Show badging in WifiSettings picker.

Bug: 33457699, 33778046
Test: Unit tests
Change-Id: Icc3161cf147b3a9715d6e9f56af574e52ae6c832
parent 4ea4f63d
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.net;

import android.annotation.SystemApi;
import android.net.wifi.ScanResult;
import android.os.Parcel;
import android.os.Parcelable;

@@ -51,6 +52,18 @@ public class NetworkKey implements Parcelable {
     */
    public final WifiKey wifiKey;

    /**
     * Constructs a new NetworkKey for the given wifi {@link ScanResult}.
     *
     * @throws IllegalArgumentException if the given ScanResult is malformed
     * @hide
     */
    public static NetworkKey createFromScanResult(ScanResult result) {
        return new NetworkKey(
                new WifiKey(
                        '"' + result.wifiSsid.toString() + '"', result.BSSID));
    }

    /**
     * Construct a new {@link NetworkKey} for a Wi-Fi network.
     * @param wifiKey the {@link WifiKey} identifying this Wi-Fi network.
+53 −0
Original line number Diff line number Diff line
@@ -27,12 +27,15 @@ import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.State;
import android.net.NetworkKey;
import android.net.ScoredNetwork;
import android.net.wifi.IWifiManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkScoreCache;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -48,6 +51,7 @@ import android.util.Log;
import com.android.settingslib.R;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@@ -132,6 +136,9 @@ public class AccessPoint implements Comparable<AccessPoint> {

    private Object mTag;

    private int mRankingScore = Integer.MIN_VALUE;
    private int mBadge = ScoredNetwork.BADGING_NONE;

    // used to co-relate internal vs returned accesspoint.
    int mId;

@@ -205,6 +212,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
        this.mScanResultCache.clear();
        this.mScanResultCache.putAll(that.mScanResultCache);
        this.mId = that.mId;
        this.mBadge = that.mBadge;
        this.mRankingScore = that.mRankingScore;
    }

    @Override
@@ -213,6 +222,11 @@ public class AccessPoint implements Comparable<AccessPoint> {
        if (isActive() && !other.isActive()) return -1;
        if (!isActive() && other.isActive()) return 1;

        // Higher scores go before lower scores
        if (mRankingScore != other.mRankingScore) {
            return (mRankingScore > other.mRankingScore) ? -1 : 1;
        }

        // Reachable one goes before unreachable one.
        if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1;
        if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1;
@@ -268,9 +282,38 @@ public class AccessPoint implements Comparable<AccessPoint> {
        if (security != SECURITY_NONE) {
            builder.append(',').append(securityToString(security, pskType));
        }
        builder.append(",rankingScore=").append(mRankingScore);
        builder.append(",badge=").append(mBadge);

        return builder.append(')').toString();
    }

    /**
     * Updates the AccessPoint rankingScore and badge, returning true if the data has changed.
     *
     * @param scoreCache The score cache to use to retrieve scores.
     */
    boolean updateScores(WifiNetworkScoreCache scoreCache) {
        int oldBadge = mBadge;
        int oldRankingScore = mRankingScore;
        mBadge = ScoredNetwork.BADGING_NONE;
        mRankingScore = Integer.MIN_VALUE;

        for (ScanResult result : mScanResultCache.values()) {
            ScoredNetwork score = scoreCache.getScoredNetwork(result);
            if (score == null) {
                continue;
            }

            if (score.hasRankingScore()) {
                mRankingScore = Math.max(mRankingScore, score.calculateRankingScore(result.level));
            }
            mBadge = Math.max(mBadge, score.calculateBadge(result.level));
        }

        return (oldBadge != mBadge || oldRankingScore != mRankingScore);
    }

    private void evictOldScanResults() {
        long nowMs = SystemClock.elapsedRealtime();
        for (Iterator<ScanResult> iter = mScanResultCache.values().iterator(); iter.hasNext(); ) {
@@ -555,6 +598,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
            visibility.append(" rssi=").append(mInfo.getRssi());
            visibility.append(" ");
            visibility.append(" score=").append(mInfo.score);
            visibility.append(" rankingScore=").append(getRankingScore());
            visibility.append(" badge=").append(getBadge());
            visibility.append(String.format(" tx=%.1f,", mInfo.txSuccessRate));
            visibility.append(String.format("%.1f,", mInfo.txRetriesRate));
            visibility.append(String.format("%.1f ", mInfo.txBadRate));
@@ -820,6 +865,14 @@ public class AccessPoint implements Comparable<AccessPoint> {
        mRssi = rssi;
    }

    int getRankingScore() {
        return mRankingScore;
    }

    int getBadge() {
        return mBadge;
    }

    public static String getSummary(Context context, String ssid, DetailedState state,
            boolean isEphemeral, String passpointProvider) {
        if (state == DetailedState.CONNECTED && ssid == null) {
+145 −22
Original line number Diff line number Diff line
@@ -24,15 +24,22 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkKey;
import android.net.NetworkRequest;
import android.net.NetworkScoreManager;
import android.net.ScoredNetwork;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiNetworkScoreCache.CacheListener;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.WorkerThread;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -49,14 +56,18 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Tracks saved or available wifi networks and their state.
 */
public class WifiTracker {
    // TODO(sghuman): Document remaining methods with @UiThread and @WorkerThread where possible.
    // TODO(sghuman): Refactor to avoid calling certain methods on the UiThread.

    private static final String TAG = "WifiTracker";
    private static final boolean DBG = false;
    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);

    /** verbose logging flag. this flag is set thru developer debugging options
     * and used so as to assist with in-the-field WiFi connectivity debugging  */
@@ -122,6 +133,10 @@ public class WifiTracker {
    private NetworkInfo mLastNetworkInfo;
    private WifiInfo mLastInfo;

    private final NetworkScoreManager mNetworkScoreManager;
    private final WifiNetworkScoreCache mScoreCache;
    private final Set<NetworkKey> mRequestedScores = new ArraySet<>();

    @VisibleForTesting
    Scanner mScanner;

@@ -144,14 +159,16 @@ public class WifiTracker {
            boolean includeSaved, boolean includeScans, boolean includePasspoints) {
        this(context, wifiListener, workerLooper, includeSaved, includeScans, includePasspoints,
                context.getSystemService(WifiManager.class),
                context.getSystemService(ConnectivityManager.class), Looper.myLooper());
                context.getSystemService(ConnectivityManager.class),
                context.getSystemService(NetworkScoreManager.class), Looper.myLooper()
        );
    }

    @VisibleForTesting
    WifiTracker(Context context, WifiListener wifiListener, Looper workerLooper,
            boolean includeSaved, boolean includeScans, boolean includePasspoints,
            WifiManager wifiManager, ConnectivityManager connectivityManager,
            Looper currentLooper) {
            NetworkScoreManager networkScoreManager, Looper currentLooper) {
        if (!includeSaved && !includeScans) {
            throw new IllegalArgumentException("Must include either saved or scans");
        }
@@ -186,6 +203,18 @@ public class WifiTracker {
                .clearCapabilities()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .build();

        mNetworkScoreManager = networkScoreManager;

        mScoreCache = new WifiNetworkScoreCache(context, new CacheListener(mWorkHandler) {
            @Override
            public void networkCacheUpdated(List<ScoredNetwork> networks) {
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    Log.v(TAG, "Score cache was updated with networks: " + networks);
                }
                Message.obtain(mWorkHandler, WorkHandler.MSG_UPDATE_NETWORK_SCORES).sendToTarget();
            }
        });
    }

    /**
@@ -216,6 +245,8 @@ public class WifiTracker {

    /**
     * Resume scanning for wifi networks after it has been paused.
     *
     * <p>The score cache should be registered before this method is invoked.
     */
    public void resumeScanning() {
        if (mScanner == null) {
@@ -230,11 +261,20 @@ public class WifiTracker {
    }

    /**
     * Start tracking wifi networks.
     * Registers listeners and starts scanning for wifi networks. If this is not called
     * Start tracking wifi networks and scores.
     *
     * <p>Registers listeners and starts scanning for wifi networks. If this is not called
     * then forceUpdate() must be called to populate getAccessPoints().
     */
    public void startTracking() {
        mWorkHandler.post(new Runnable() {
            @Override
            public void run() {
                registerScoreCache();
            }
        });


        resumeScanning();
        if (!mRegistered) {
            mContext.registerReceiver(mReceiver, mFilter);
@@ -245,9 +285,28 @@ public class WifiTracker {
        }
    }

    @WorkerThread
    private void registerScoreCache() {
        mNetworkScoreManager.registerNetworkScoreCache(
                NetworkKey.TYPE_WIFI,
                mScoreCache,
                NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS);
    }

    private void requestScoresForNetworkKeys(Collection<NetworkKey> keys) {
        if (keys.isEmpty()) return;

        if (DBG) {
            Log.d(TAG, "Requesting scores for Network Keys: " + keys);
        }
        mNetworkScoreManager.requestScores(keys.toArray(new NetworkKey[keys.size()]));
        mRequestedScores.addAll(keys);
    }

    /**
     * Stop tracking wifi networks.
     * Unregisters all listeners and stops scanning for wifi networks. This should always
     * Stop tracking wifi networks and scores.
     *
     * <p>Unregisters all listeners and stops scanning for wifi networks. This should always
     * be called when done with a WifiTracker (if startTracking was called) to ensure
     * proper cleanup.
     */
@@ -255,11 +314,26 @@ public class WifiTracker {
        if (mRegistered) {
            mWorkHandler.removeMessages(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
            mWorkHandler.removeMessages(WorkHandler.MSG_UPDATE_NETWORK_INFO);
            mWorkHandler.removeMessages(WorkHandler.MSG_UPDATE_NETWORK_SCORES);
            mContext.unregisterReceiver(mReceiver);
            mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
            mRegistered = false;
        }
        pauseScanning();

        mWorkHandler.post(new Runnable() {
            @Override
            public void run() {
                unregisterAndClearScoreCache();
            }
        });
    }

    @WorkerThread
    private void unregisterAndClearScoreCache() {
        mRequestedScores.clear();
        mNetworkScoreManager.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, mScoreCache);
        mScoreCache.clearScores();
    }

    /**
@@ -415,6 +489,7 @@ public class WifiTracker {
            }
        }

        final List<NetworkKey> scoresToRequest = new ArrayList<>();
        if (results != null) {
            for (ScanResult result : results) {
                // Ignore hidden and ad-hoc networks.
@@ -423,6 +498,11 @@ public class WifiTracker {
                    continue;
                }

                NetworkKey key = NetworkKey.createFromScanResult(result);
                if (!mRequestedScores.contains(key)) {
                    scoresToRequest.add(key);
                }

                boolean found = false;
                for (AccessPoint accessPoint : apMap.getAll(result.SSID)) {
                    if (accessPoint.update(result)) {
@@ -457,11 +537,18 @@ public class WifiTracker {
            }
        }


        requestScoresForNetworkKeys(scoresToRequest);
        for (AccessPoint ap : accessPoints) {
            ap.updateScores(mScoreCache);
        }

        // 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 ------");
        if (DBG) {
            Log.d(TAG, "------ Dumping SSIDs that were not seen on this scan ------");
            for (AccessPoint prevAccessPoint : mInternalAccessPoints) {
                if (prevAccessPoint.getSsid() == null)
                    continue;
@@ -475,9 +562,10 @@ public class WifiTracker {
                    }
                }
                if (!found)
                if (DBG) Log.d(TAG, "Did not find " + prevSsid + " in this scan");
                    Log.d(TAG, "Did not find " + prevSsid + " in this scan");
            }
            Log.d(TAG, "---- Done dumping SSIDs that were not seen on this scan ----");
        }
        if (DBG) Log.d(TAG, "---- Done dumping SSIDs that were not seen on this scan ----");

        mInternalAccessPoints.clear();
        mInternalAccessPoints.addAll(accessPoints);
@@ -549,7 +637,38 @@ public class WifiTracker {

        boolean reorder = false;
        for (int i = mInternalAccessPoints.size() - 1; i >= 0; --i) {
            if (mInternalAccessPoints.get(i).update(connectionConfig, mLastInfo, mLastNetworkInfo)) {
            AccessPoint ap = mInternalAccessPoints.get(i);
            if (ap.update(connectionConfig, mLastInfo, mLastNetworkInfo)) {
                reorder = true;
            }
            if (ap.updateScores(mScoreCache)) {
                reorder = true;
            }
        }
        if (reorder) {
            Collections.sort(mInternalAccessPoints);
            mMainHandler.scheduleAPCopyingAndCloseWriteLock();
        }
    }

    /**
     * Update all the internal access points rankingScores and badge.
     *
     * <p>Will trigger a resort and notify listeners of changes if applicable.
     */
    private void updateNetworkScores() {
        // Lock required to prevent accidental copying of AccessPoint states while the modification
        // is in progress. see #copyAndNotifyListeners
        long before = System.currentTimeMillis();
        mInternalAccessPointsWriteLock.block();
        if (DBG) {
            Log.d(TAG, "Acquired AP lock on WorkerHandler for inserting NetworkScores. Wait time = " +
                    (System.currentTimeMillis() - before) + "ms.");
        }

        boolean reorder = false;
        for (int i = 0; i < mInternalAccessPoints.size(); i++) {
            if (mInternalAccessPoints.get(i).updateScores(mScoreCache)) {
                reorder = true;
            }
        }
@@ -661,6 +780,7 @@ public class WifiTracker {
        private static final int MSG_UPDATE_NETWORK_INFO = 1;
        private static final int MSG_RESUME = 2;
        private static final int MSG_UPDATE_WIFI_STATE = 3;
        private static final int MSG_UPDATE_NETWORK_SCORES = 4;

        public WorkHandler(Looper looper) {
            super(looper);
@@ -695,6 +815,9 @@ public class WifiTracker {
                    mMainHandler.obtainMessage(MainHandler.MSG_WIFI_STATE_CHANGED, msg.arg1, 0)
                            .sendToTarget();
                    break;
                case MSG_UPDATE_NETWORK_SCORES:
                    updateNetworkScores();
                    break;
            }
        }
    }
+1 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY"/>
    <uses-permission android:name="android.permission.SET_TIME_ZONE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />


    <application>
+369 −4

File changed.

Preview size limit exceeded, changes collapsed.

Loading