WifiAutoJoinController.java revision 68fee36dac1dda5c596c00ef33fdbc0962e9ec9f
1f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle/*
262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle * Copyright (C) 2014 The Android Open Source Project
3f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
4f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * Licensed under the Apache License, Version 2.0 (the "License");
5f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * you may not use this file except in compliance with the License.
6f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * You may obtain a copy of the License at
7f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
8f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *      http://www.apache.org/licenses/LICENSE-2.0
9f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
10f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * Unless required by applicable law or agreed to in writing, software
11f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * distributed under the License is distributed on an "AS IS" BASIS,
12f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * See the License for the specific language governing permissions and
14f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * limitations under the License.
15f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle */
16f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
17f22d23092ab37286a5ef9d257d5bb32c421d2669vandwallepackage com.android.server.wifi;
18f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
19f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.content.Context;
20f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.NetworkKey;
21f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.NetworkScoreManager;
220c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport android.net.WifiKey;
23c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalleimport android.net.wifi.*;
248639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidsonimport android.net.wifi.WifiConfiguration.KeyMgmt;
25c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalleimport android.text.TextUtils;
26f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.util.Log;
27f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
280c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport java.util.ArrayList;
29f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.Iterator;
30f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.HashMap;
31f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.List;
32f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
33f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle/**
34f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * AutoJoin controller is responsible for WiFi Connect decision
35f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
36f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * It runs in the thread context of WifiStateMachine
37f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
38f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle */
39f22d23092ab37286a5ef9d257d5bb32c421d2669vandwallepublic class WifiAutoJoinController {
40f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
41f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private Context mContext;
42f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiStateMachine mWifiStateMachine;
43f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiConfigStore mWifiConfigStore;
44f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNative mWifiNative;
45f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
46f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private NetworkScoreManager scoreManager;
47f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNetworkScoreCache mNetworkScoreCache;
48f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
49f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final String TAG = "WifiAutoJoinController ";
50ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean DBG = false;
51ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean VDBG = false;
52f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final boolean mStaStaSupported = false;
53f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
54c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    public static int mScanResultMaximumAge = 40000; /* milliseconds unit */
55c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
56453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle    private String mCurrentConfigurationKey = null; //used by autojoin
57f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
58f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private HashMap<String, ScanResult> scanResultCache =
59f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            new HashMap<String, ScanResult>();
60f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
61c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    private WifiConnectionStatistics mWifiConnectionStatistics;
62c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
638639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    /** Whether to allow connections to untrusted networks. */
648639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    private boolean mAllowUntrustedConnections = false;
658639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
66c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    /* for debug purpose only : the untrusted SSID we would be connected to if we had VPN */
67c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    String lastUntrustedBSSID = null;
68c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
69c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    /* For debug purpose only: if the scored override a score */
70c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    boolean didOverride = false;
71c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
72931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Lose the non-auth failure blacklisting after 8 hours
734dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListHardMilli = 1000 * 60 * 60 * 8;
74931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Lose some temporary blacklisting after 30 minutes
754dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListSoftMilli = 1000 * 60 * 30;
7627355a942653264388e909a4276196ee63e57811vandwalle
77b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_IDLE = 0;
78b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_ROAMING = 1;
79b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_EXTENDED_ROAMING = 2;
80b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_OUT_OF_NETWORK_ROAMING = 3;
81b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
8297b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle    public static final int HIGH_THRESHOLD_MODIFIER = 5;
8397b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle
841ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    // Below are AutoJoin wide parameters indicating if we should be aggressive before joining
851ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    // weak network. Note that we cannot join weak network that are going to be marked as unanted by
861ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    // ConnectivityService because this will trigger link flapping.
871ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    /**
881ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     * There was a non-blacklisted configuration that we bailed from because of a weak signal
891ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     */
901ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    boolean didBailDueToWeakRssi = false;
911ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    /**
921ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     * number of time we consecutively bailed out of an eligible network because its signal
931ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     * was too weak
941ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     */
951ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    int weakRssiBailCount = 0;
961ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle
97f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    WifiAutoJoinController(Context c, WifiStateMachine w, WifiConfigStore s,
98c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                           WifiConnectionStatistics st, WifiNative n) {
99f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mContext = c;
100f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiStateMachine = w;
101f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore = s;
102f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiNative = n;
103f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mNetworkScoreCache = null;
104c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        mWifiConnectionStatistics = st;
10521bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle        scoreManager =
10621bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                (NetworkScoreManager) mContext.getSystemService(Context.NETWORK_SCORE_SERVICE);
107f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager == null)
108f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("Registered scoreManager NULL " + " service " + Context.NETWORK_SCORE_SERVICE);
109f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
110f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager != null) {
111f13817203179f41620514718c8668ae7e418f8afJeff Davidson            mNetworkScoreCache = new WifiNetworkScoreCache(mContext);
112f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            scoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
113f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        } else {
114f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("No network score service: Couldnt register as a WiFi score Manager, type="
115f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(NetworkKey.TYPE_WIFI)
116f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + " service " + Context.NETWORK_SCORE_SERVICE);
117f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            mNetworkScoreCache = null;
118f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
119f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
120f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
121ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    void enableVerboseLogging(int verbose) {
122ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (verbose > 0 ) {
123abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = true;
124ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = true;
125ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        } else {
126abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = false;
127ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = false;
128ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
129ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    }
130ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle
131931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
132931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * Flush out scan results older than mScanResultMaximumAge
133ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     *
134931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
135f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private void ageScanResultsOut(int delay) {
136f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (delay <= 0) {
137931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            delay = mScanResultMaximumAge; // Something sane
138f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
139b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        long milli = System.currentTimeMillis();
140f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
141f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("ageScanResultsOut delay " + Integer.valueOf(delay) + " size "
142f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.valueOf(scanResultCache.size()) + " now " + Long.valueOf(milli));
143f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
144f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
145f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        Iterator<HashMap.Entry<String,ScanResult>> iter = scanResultCache.entrySet().iterator();
146f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        while (iter.hasNext()) {
147f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            HashMap.Entry<String,ScanResult> entry = iter.next();
148f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult result = entry.getValue();
149f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
150f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((result.seen + delay) < milli) {
151f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                iter.remove();
152f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
153f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
154f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
155f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
156be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle    int addToScanCache(List<ScanResult> scanList) {
157be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        int numScanResultsKnown = 0; // Record number of scan results we knew about
158be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        WifiConfiguration associatedConfig = null;
1597b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle        boolean didAssociate = false;
160f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1610c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        ArrayList<NetworkKey> unknownScanResults = new ArrayList<NetworkKey>();
1620c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
163f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for(ScanResult result: scanList) {
1641fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng            if (result.SSID == null) continue;
165c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
166c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // Make sure we record the last time we saw this result
167f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            result.seen = System.currentTimeMillis();
168f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
169c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // Fetch the previous instance for this result
170f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult sr = scanResultCache.get(result.BSSID);
171f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (sr != null) {
172931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // If there was a previous cache result for this BSSID, average the RSSI values
173c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                result.averageRssi(sr.level, sr.seen, mScanResultMaximumAge);
174f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
175c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                // Remove the previous Scan Result - this is not necessary
176f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                scanResultCache.remove(result.BSSID);
177e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            }
178e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle
179e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            if (!mNetworkScoreCache.isScoredNetwork(result)) {
180e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                WifiKey wkey;
181e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                // Quoted SSIDs are the only one valid at this stage
182e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                try {
183e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    wkey = new WifiKey("\"" + result.SSID + "\"", result.BSSID);
184e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                } catch (IllegalArgumentException e) {
185e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg("AutoJoinController: received badly encoded SSID=[" + result.SSID +
186e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                            "] ->skipping this network");
187e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    wkey = null;
188e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                }
189e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (wkey != null) {
190e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    NetworkKey nkey = new NetworkKey(wkey);
191e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    //if we don't know this scan result then request a score from the scorer
192e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    unknownScanResults.add(nkey);
193e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                }
194e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (VDBG) {
1957b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    String cap = "";
1967b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    if (result.capabilities != null)
1977b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                        cap = result.capabilities;
198e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg(result.SSID + " " + result.BSSID + " rssi="
1997b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                            + result.level + " cap " + cap + " is not scored");
200e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                }
2010c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            } else {
202e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (VDBG) {
2037b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    String cap = "";
2047b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    if (result.capabilities != null)
2057b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                        cap = result.capabilities;
206e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    int score = mNetworkScoreCache.getNetworkScore(result);
207e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg(result.SSID + " " + result.BSSID + " rssi="
2087b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                            + result.level + " cap " + cap + " is scored : " + score);
2090c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                }
210f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
211f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
212e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // scanResultCache.put(result.BSSID, new ScanResult(result));
213e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            scanResultCache.put(result.BSSID, result);
214be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            // Add this BSSID to the scanResultCache of a Saved WifiConfiguration
2157b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle            didAssociate = mWifiConfigStore.updateSavedNetworkHistory(result);
216f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
217be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            // If not successful, try to associate this BSSID to an existing Saved WifiConfiguration
2187b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle            if (!didAssociate) {
219be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                // We couldn't associate the scan result to a Saved WifiConfiguration
220c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                // Hence it is untrusted
221c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                result.untrusted = true;
222f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                associatedConfig = mWifiConfigStore.associateWithConfiguration(result);
2231fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng                if (associatedConfig != null && associatedConfig.SSID != null) {
224f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (VDBG) {
225f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        logDbg("addToScanCache save associated config "
2267b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                                + associatedConfig.SSID + " with " + result.SSID);
227f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
228be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                    mWifiStateMachine.sendMessage(
229be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                            WifiStateMachine.CMD_AUTO_SAVE_NETWORK, associatedConfig);
2307b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    didAssociate = true;
231f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
2320d616ef3bf635dff8722e064c0be842676390ed8vandwalle            } else {
2330d616ef3bf635dff8722e064c0be842676390ed8vandwalle                // If the scan result has been blacklisted fir 18 hours -> unblacklist
2340d616ef3bf635dff8722e064c0be842676390ed8vandwalle                long now = System.currentTimeMillis();
2350d616ef3bf635dff8722e064c0be842676390ed8vandwalle                if ((now - result.blackListTimestamp) > loseBlackListHardMilli) {
2360d616ef3bf635dff8722e064c0be842676390ed8vandwalle                    result.setAutoJoinStatus(ScanResult.ENABLED);
2370d616ef3bf635dff8722e064c0be842676390ed8vandwalle                }
238f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
2397b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle            if (didAssociate) {
240be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                numScanResultsKnown++;
241a0708b09ad17b086c008ab100aec7143d7613c80vandwalle                result.isAutoJoinCandidate ++;
242a0708b09ad17b086c008ab100aec7143d7613c80vandwalle            } else {
243a0708b09ad17b086c008ab100aec7143d7613c80vandwalle                result.isAutoJoinCandidate = 0;
244be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            }
245f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
2460c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
2470c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        if (unknownScanResults.size() != 0) {
2480c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            NetworkKey[] newKeys =
2490c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                    unknownScanResults.toArray(new NetworkKey[unknownScanResults.size()]);
250931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Kick the score manager, we will get updated scores asynchronously
2510c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            scoreManager.requestScores(newKeys);
2520c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        }
253be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        return numScanResultsKnown;
254f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
255f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
256f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void logDbg(String message) {
2570888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle        logDbg(message, false);
258ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    }
259ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
260ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    void logDbg(String message, boolean stackTrace) {
261ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (stackTrace) {
2622f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            Log.e(TAG, message + " stack:"
263ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[2].getMethodName() + " - "
264ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[3].getMethodName() + " - "
265ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[4].getMethodName() + " - "
266ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[5].getMethodName());
267ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        } else {
2682f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            Log.e(TAG, message);
269ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        }
270f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
271f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
272931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Called directly from WifiStateMachine
273be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle    int newSupplicantResults(boolean doAutoJoin) {
274be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        int numScanResultsKnown;
275e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        List<ScanResult> scanList = mWifiStateMachine.getScanResultsListNoCopyUnsync();
276be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        numScanResultsKnown = addToScanCache(scanList);
277f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(mScanResultMaximumAge);
278be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        if (DBG) {
279be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            logDbg("newSupplicantResults size=" + Integer.valueOf(scanResultCache.size())
2802f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        + " known=" + numScanResultsKnown + " "
2819f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                        + doAutoJoin);
282be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        }
2837806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle        if (doAutoJoin) {
2847806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            attemptAutoJoin();
2857806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle        }
286005c1ef113192f898499a407dd266393a8d6b076vandwalle        mWifiConfigStore.writeKnownNetworkHistory(false);
287be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        return numScanResultsKnown;
288f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
289f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
290f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
291931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
292931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * Not used at the moment
293f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * should be a call back from WifiScanner HAL ??
294f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * this function is not hooked and working yet, it will receive scan results from WifiScanners
295f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * with the list of IEs,then populate the capabilities by parsing the IEs and inject the scan
296f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * results as normal.
297f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     */
298f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void newHalScanResults() {
299f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        List<ScanResult> scanList = null;//mWifiScanner.syncGetScanResultsList();
300f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String akm = WifiParser.parse_akm(null, null);
301f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        logDbg(akm);
302f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        addToScanCache(scanList);
303f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(0);
304f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
305005c1ef113192f898499a407dd266393a8d6b076vandwalle        mWifiConfigStore.writeKnownNetworkHistory(false);
306f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
307f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
308931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
309931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     *  network link quality changed, called directly from WifiTrafficPoller,
310931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * or by listening to Link Quality intent
311931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
312f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void linkQualitySignificantChange() {
313f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
314f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
315f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
316931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
317f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * compare a WifiConfiguration against the current network, return a delta score
318f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * If not associated, and the candidate will always be better
319f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * For instance if the candidate is a home network versus an unknown public wifi,
320f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * the delta will be infinite, else compare Kepler scores etc…
321b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * Negatve return values from this functions are meaningless per se, just trying to
322b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * keep them distinct for debug purpose (i.e. -1, -2 etc...)
323931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
324e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle    private int compareNetwork(WifiConfiguration candidate,
325e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                               String lastSelectedConfiguration) {
326b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (candidate == null)
327b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -3;
328b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
329f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration currentNetwork = mWifiStateMachine.getCurrentWifiConfiguration();
330b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentNetwork == null) {
331c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // Return any absurdly high score, if we are not connected there is no current
332c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // network to...
333b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle           return 1000;
334b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
335f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
336f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (candidate.configKey(true).equals(currentNetwork.configKey(true))) {
337b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -2;
338f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
339f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
340b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle        if (DBG) {
341e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            logDbg("compareNetwork will compare " + candidate.configKey()
342e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    + " with current " + currentNetwork.configKey());
343b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle        }
344c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        int order = compareWifiConfigurationsTop(currentNetwork, candidate);
345e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle
346e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // The lastSelectedConfiguration is the configuration the user has manually selected
347e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // thru WifiPicker, or that a 3rd party app asked us to connect to via the
348e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // enableNetwork with disableOthers=true WifiManager API
349e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // As this is a direct user choice, we strongly prefer this configuration,
350e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // hence give +/-100
351e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        if ((lastSelectedConfiguration != null)
352e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                && currentNetwork.configKey().equals(lastSelectedConfiguration)) {
353e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // currentNetwork is the last selected configuration,
354e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // so keep it above connect choices (+/-60) and
355e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // above RSSI/scorer based selection of linked configuration (+/- 50)
356e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // by reducing order by -100
357e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            order = order - 100;
358e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            if (VDBG)   {
359e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("     ...and prefers -100 " + currentNetwork.configKey()
360e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " over " + candidate.configKey()
361e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " because it is the last selected -> "
362e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + Integer.toString(order));
363e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            }
364e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        } else if ((lastSelectedConfiguration != null)
365e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                && candidate.configKey().equals(lastSelectedConfiguration)) {
366e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // candidate is the last selected configuration,
367e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // so keep it above connect choices (+/-60) and
368e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // above RSSI/scorer based selection of linked configuration (+/- 50)
369e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // by increasing order by +100
370e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            order = order + 100;
371e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            if (VDBG)   {
372e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("     ...and prefers +100 " + candidate.configKey()
373e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " over " + currentNetwork.configKey()
374e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " because it is the last selected -> "
375e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + Integer.toString(order));
376e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            }
377e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        }
378e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle
379ede507649471f1113e9e1919812115ca5a6bc0c8vandwalle        return order;
380f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
381f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
382ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    /**
383ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * update the network history fields fo that configuration
384ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if userTriggered, we mark the configuration as "non selfAdded" since the user has seen it
385ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * and took over management
386ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if it is a "connect", remember which network were there at the point of the connect, so
387ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * as those networks get a relative lower score than the selected configuration
38862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle     *
389ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param netId
390ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param userTriggered : if the update come from WiFiManager
391ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param connect : if the update includes a connect
392931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
39362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle    public void updateConfigurationHistory(int netId, boolean userTriggered, boolean connect) {
394f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration selected = mWifiConfigStore.getWifiConfiguration(netId);
395f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (selected == null) {
396c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory nid=" + netId + " no selected configuration!");
397f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return;
398f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
399f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
400e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        if (selected.SSID == null) {
401c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory nid=" + netId +
402c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    " no SSID in selected configuration!");
403e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            return;
404e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        }
405e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
40662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        if (userTriggered) {
407931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Reenable autojoin for this network,
40862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            // since the user want to connect to this configuration
40927355a942653264388e909a4276196ee63e57811vandwalle            selected.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
41062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            selected.selfAdded = false;
411e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            selected.dirty = true;
41262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        }
413f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
414992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (DBG && userTriggered) {
415f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (selected.connectChoices != null) {
416ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
417f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + Integer.toString(netId) + " now: "
418992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(selected.connectChoices.size())
419992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
420f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
421ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
422992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(netId)
423992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
424f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
425f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
426f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
427ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (connect && userTriggered) {
428ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            boolean found = false;
4292451dbcc4f9641df188326215b204b798eb70c46vandwalle            int choice = 0;
430c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            int size = 0;
4319f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
4329f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // Reset the triggered disabled count, because user wanted to connect to this
4339f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // configuration, and we were not.
4349f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableLowRSSI = 0;
4359f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableBadRSSI = 0;
4369f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableNotHighRSSI = 0;
4379f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredJoinAttempts++;
4389f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
43962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            List<WifiConfiguration> networks =
44062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    mWifiConfigStore.getRecentConfiguredNetworks(12000, false);
441c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (networks != null) size = networks.size();
442c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory found " + size + " networks");
44362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            if (networks != null) {
44462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                for (WifiConfiguration config : networks) {
445992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    if (DBG) {
446992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        logDbg("updateConfigurationHistory got " + config.SSID + " nid="
447992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                                + Integer.toString(config.networkId));
448992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    }
449f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
45062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (selected.configKey(true).equals(config.configKey(true))) {
451ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        found = true;
45262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        continue;
45362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
454f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
4552451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // Compare RSSI values so as to evaluate the strength of the user preference
4562451dbcc4f9641df188326215b204b798eb70c46vandwalle                    int order = compareWifiConfigurationsRSSI(config, selected, null);
4572451dbcc4f9641df188326215b204b798eb70c46vandwalle
4582451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (order < -30) {
4592451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is worse than the visible configuration
4602451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence register a strong choice so as autojoin cannot override this
4612451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // for instance, the user has select a network
4622451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // with 1 bar over a network with 3 bars...
4632451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 60;
4642451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order < -20) {
4652451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 50;
4662451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order < -10) {
4672451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 40;
4682f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    } else if (order < 20) {
4692451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is about same or has a slightly better RSSI
4702451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence register a weaker choice, here a difference of at least +/-30 in
4712451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // RSSI comparison triggered by autoJoin will override the choice
4722451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 30;
4732f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    } else {
4742451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is better than the visible configuration
4752451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence we do not know if the user prefers this configuration strongly
4762451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 20;
47762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
478f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
479931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // The selected configuration was preferred over a recently seen config
480931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // hence remember the user's choice:
481931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // add the recently seen config to the selected's connectChoices array
482ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
483ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    if (selected.connectChoices == null) {
484ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        selected.connectChoices = new HashMap<String, Integer>();
485ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    }
486ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
487ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    logDbg("updateConfigurationHistory add a choice " + selected.configKey(true)
4880888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                            + " over " + config.configKey(true)
4892451dbcc4f9641df188326215b204b798eb70c46vandwalle                            + " choice " + Integer.toString(choice));
490cf5b8eb8a08c45bd4a82f1f4bb789c8a1b08744fvandwalle
4912451dbcc4f9641df188326215b204b798eb70c46vandwalle                    Integer currentChoice = selected.connectChoices.get(config.configKey(true));
4922f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    if (currentChoice != null) {
4932f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // User has made this choice multiple time in a row, so bump up a lot
4942f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        choice += currentChoice.intValue();
4952451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
4962f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // Add the visible config to the selected's connect choice list
4972f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    selected.connectChoices.put(config.configKey(true), choice);
498f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
49962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (config.connectChoices != null) {
500ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        if (VDBG) {
501ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                            logDbg("updateConfigurationHistory will remove "
50262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                    + selected.configKey(true) + " from " + config.configKey(true));
503ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        }
504931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Remove the selected from the recently seen config's connectChoice list
50562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        config.connectChoices.remove(selected.configKey(true));
5060888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle
5070888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        if (selected.linkedConfigurations != null) {
508931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                           // Remove the selected's linked configuration from the
509931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                           // recently seen config's connectChoice list
5100888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           for (String key : selected.linkedConfigurations.keySet()) {
5110888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                               config.connectChoices.remove(key);
5120888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           }
5130888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        }
51462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
515ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                }
516ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                if (found == false) {
5172451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // We haven't found the configuration that the user just selected in our
5182451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // scan cache.
5192451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // In that case we will need a new scan before attempting to connect to this
5202451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // configuration anyhow and thus we can process the scan results then.
521ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     logDbg("updateConfigurationHistory try to connect to an old network!! : "
522ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                             + selected.configKey());
52362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
524f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
52562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                if (selected.connectChoices != null) {
52662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (VDBG)
527ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        logDbg("updateConfigurationHistory " + Integer.toString(netId)
52862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                + " now: " + Integer.toString(selected.connectChoices.size()));
52962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
530f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
531f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
532992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle
533931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // TODO: write only if something changed
534992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (userTriggered || connect) {
535005c1ef113192f898499a407dd266393a8d6b076vandwalle            mWifiConfigStore.writeKnownNetworkHistory(false);
536992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        }
537f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
538f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
5392451dbcc4f9641df188326215b204b798eb70c46vandwalle    int getConnectChoice(WifiConfiguration source, WifiConfiguration target) {
5402451dbcc4f9641df188326215b204b798eb70c46vandwalle        Integer choice = null;
5412451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (source == null || target == null) {
5422451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
543f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
544f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
5452451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (source.connectChoices != null
5462451dbcc4f9641df188326215b204b798eb70c46vandwalle                && source.connectChoices.containsKey(target.configKey(true))) {
5472451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = source.connectChoices.get(target.configKey(true));
5482451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else if (source.linkedConfigurations != null) {
549f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            for (String key : source.linkedConfigurations.keySet()) {
550f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(key);
551f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (config != null) {
552f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (config.connectChoices != null) {
5532451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = config.connectChoices.get(target.configKey(true));
554f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
555f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
556f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
5572451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
5582451dbcc4f9641df188326215b204b798eb70c46vandwalle
5592451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (choice == null) {
5602451dbcc4f9641df188326215b204b798eb70c46vandwalle            //We didn't find the connect choice
5612451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
5622451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else {
5632451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice.intValue() < 0) {
5642451dbcc4f9641df188326215b204b798eb70c46vandwalle                choice = 20; // Compatibility with older files
5652451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
5662451dbcc4f9641df188326215b204b798eb70c46vandwalle            return choice.intValue();
5672451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
5682451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
5692451dbcc4f9641df188326215b204b798eb70c46vandwalle
5702451dbcc4f9641df188326215b204b798eb70c46vandwalle
5719f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle    int getScoreFromVisibility(WifiConfiguration.Visibility visibility, int rssiBoost, String dbg) {
5722451dbcc4f9641df188326215b204b798eb70c46vandwalle        int rssiBoost5 = 0;
5732451dbcc4f9641df188326215b204b798eb70c46vandwalle        int score = 0;
5744dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
5752451dbcc4f9641df188326215b204b798eb70c46vandwalle        /**
5762451dbcc4f9641df188326215b204b798eb70c46vandwalle         * Boost RSSI value of 5GHz bands iff the base value is better than threshold
5772451dbcc4f9641df188326215b204b798eb70c46vandwalle         * This implements band preference where we prefer 5GHz if RSSI5 is good enough, whereas
5782451dbcc4f9641df188326215b204b798eb70c46vandwalle         * we prefer 2.4GHz otherwise.
5792451dbcc4f9641df188326215b204b798eb70c46vandwalle         * Note that 2.4GHz doesn't need a boost since at equal power the RSSI is typically
580e67ec726c07410073575473c0f50dc737629f5davandwalle         * at least 6-10 dB higher
5812451dbcc4f9641df188326215b204b798eb70c46vandwalle         */
5829f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle        rssiBoost5 = rssiBoostFrom5GHzRssi(visibility.rssi5, dbg+"->");
5832451dbcc4f9641df188326215b204b798eb70c46vandwalle
5842451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Select which band to use so as to score a
5852451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (visibility.rssi5 + rssiBoost5 > visibility.rssi24) {
5862451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Prefer a's 5GHz
5872451dbcc4f9641df188326215b204b798eb70c46vandwalle            score = visibility.rssi5 + rssiBoost5 + rssiBoost;
5882451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else {
5892451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Prefer a's 2.4GHz
5902451dbcc4f9641df188326215b204b798eb70c46vandwalle            score = visibility.rssi24 + rssiBoost;
591f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
5922451dbcc4f9641df188326215b204b798eb70c46vandwalle
5932451dbcc4f9641df188326215b204b798eb70c46vandwalle        return score;
594f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
595f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
5962451dbcc4f9641df188326215b204b798eb70c46vandwalle    // Compare WifiConfiguration by RSSI, and return a comparison value in the range [-50, +50]
5972451dbcc4f9641df188326215b204b798eb70c46vandwalle    // The result represents "approximately" an RSSI difference measured in dBM
5982451dbcc4f9641df188326215b204b798eb70c46vandwalle    // Adjusted with various parameters:
5992451dbcc4f9641df188326215b204b798eb70c46vandwalle    // +) current network gets a +15 boost
6002451dbcc4f9641df188326215b204b798eb70c46vandwalle    // +) 5GHz signal, if they are strong enough, get a +15 or +25 boost, representing the
6012451dbcc4f9641df188326215b204b798eb70c46vandwalle    // fact that at short range we prefer 5GHz band as it is cleaner of interference and
6022451dbcc4f9641df188326215b204b798eb70c46vandwalle    // provides for wider channels
6032451dbcc4f9641df188326215b204b798eb70c46vandwalle    int compareWifiConfigurationsRSSI(WifiConfiguration a, WifiConfiguration b,
6042451dbcc4f9641df188326215b204b798eb70c46vandwalle                                      String currentConfiguration) {
605f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
6062451dbcc4f9641df188326215b204b798eb70c46vandwalle
6072451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Boost used so as to favor current config
6082451dbcc4f9641df188326215b204b798eb70c46vandwalle        int aRssiBoost = 0;
6092451dbcc4f9641df188326215b204b798eb70c46vandwalle        int bRssiBoost = 0;
6102451dbcc4f9641df188326215b204b798eb70c46vandwalle
6112451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreA;
6122451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreB;
6132451dbcc4f9641df188326215b204b798eb70c46vandwalle
6142451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Retrieve the visibility
615f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility astatus = a.visibility;
616f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility bstatus = b.visibility;
617f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (astatus == null || bstatus == null) {
6182451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Error visibility wasn't set
619b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurations NULL band status!");
620f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 0;
621f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
6222451dbcc4f9641df188326215b204b798eb70c46vandwalle
6232451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply Hysteresis, boost RSSI of current configuration
6242451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (null != currentConfiguration) {
6252451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (a.configKey().equals(currentConfiguration)) {
626b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                aRssiBoost = +10;
6272451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (b.configKey().equals(currentConfiguration)) {
628b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                bRssiBoost = +10;
6292451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
630b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle
631b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle
6322451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
6332451dbcc4f9641df188326215b204b798eb70c46vandwalle
6342451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG)  {
635b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsRSSI: " + a.configKey()
636c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + " " + Integer.toString(astatus.rssi24)
637c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + "," + Integer.toString(astatus.rssi5)
6382451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " boost=" + Integer.toString(aRssiBoost)
639c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + " " + b.configKey() + " "
640c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + Integer.toString(bstatus.rssi24) + ","
641c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + Integer.toString(bstatus.rssi5)
6422451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " boost=" + Integer.toString(bRssiBoost)
6432451dbcc4f9641df188326215b204b798eb70c46vandwalle            );
644f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
6452451dbcc4f9641df188326215b204b798eb70c46vandwalle
6469f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle        scoreA = getScoreFromVisibility(astatus, aRssiBoost, a.configKey());
6479f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle        scoreB = getScoreFromVisibility(bstatus, bRssiBoost, b.configKey());
6482451dbcc4f9641df188326215b204b798eb70c46vandwalle
6492451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Compare a and b
6502451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If a score is higher then a > b and the order is descending (negative)
6512451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If b score is higher then a < b and the order is ascending (positive)
6522451dbcc4f9641df188326215b204b798eb70c46vandwalle        order = scoreB - scoreA;
6532451dbcc4f9641df188326215b204b798eb70c46vandwalle
6542451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Normalize the order to [-50, +50]
6552451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (order > 50) order = 50;
6562451dbcc4f9641df188326215b204b798eb70c46vandwalle        else if (order < -50) order = -50;
6572451dbcc4f9641df188326215b204b798eb70c46vandwalle
6582451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
6592451dbcc4f9641df188326215b204b798eb70c46vandwalle            String prefer = " = ";
6602451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (order > 0) {
6612451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " < "; // Ascending
6622451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (order < 0) {
6632451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " > "; // Descending
6642451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
665b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsRSSI " + a.configKey()
6662451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + a.visibility.rssi24
6672451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.rssi5
6682451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + a.visibility.num24
6692451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.num5 + ")"
670e67ec726c07410073575473c0f50dc737629f5davandwalle                    + " scorea=" + scoreA
6712451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + prefer + b.configKey()
6722451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + b.visibility.rssi24
6732451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.rssi5
6742451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + b.visibility.num24
6752451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.num5 + ")"
676e67ec726c07410073575473c0f50dc737629f5davandwalle                    + " scoreb=" + scoreB
6772451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " -> " + order);
6782451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
6792451dbcc4f9641df188326215b204b798eb70c46vandwalle
680f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
681f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
682f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
6834dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
6842451dbcc4f9641df188326215b204b798eb70c46vandwalle    int compareWifiConfigurationsWithScorer(WifiConfiguration a, WifiConfiguration b) {
6852451dbcc4f9641df188326215b204b798eb70c46vandwalle
68681c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson        boolean aIsActive = false;
68781c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson        boolean bIsActive = false;
6882451dbcc4f9641df188326215b204b798eb70c46vandwalle
6892451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply Hysteresis : boost RSSI of current configuration before
6902451dbcc4f9641df188326215b204b798eb70c46vandwalle        // looking up the score
6912451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (null != mCurrentConfigurationKey) {
6922451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (a.configKey().equals(mCurrentConfigurationKey)) {
69381c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                aIsActive = true;
6942451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (b.configKey().equals(mCurrentConfigurationKey)) {
69581c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                bIsActive = true;
6962451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
6972451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
69881c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson        int scoreA = getConfigNetworkScore(a, 3000, aIsActive);
69981c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson        int scoreB = getConfigNetworkScore(b, 3000, bIsActive);
7002451dbcc4f9641df188326215b204b798eb70c46vandwalle
7012451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Both configurations need to have a score for the scorer to be used
7022451dbcc4f9641df188326215b204b798eb70c46vandwalle        // ...and the scores need to be different:-)
7032451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (scoreA == WifiNetworkScoreCache.INVALID_NETWORK_SCORE
7042451dbcc4f9641df188326215b204b798eb70c46vandwalle                || scoreB == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
705e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            if (VDBG)  {
706b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurationsWithScorer no-scores: "
707e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                        + a.configKey()
708e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                        + " "
709e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                        + b.configKey());
710e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            }
7112451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
7122451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
7132451dbcc4f9641df188326215b204b798eb70c46vandwalle
7142451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
7152451dbcc4f9641df188326215b204b798eb70c46vandwalle            String prefer = " = ";
7162451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (scoreA < scoreB) {
7172451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " < ";
7182451dbcc4f9641df188326215b204b798eb70c46vandwalle            } if (scoreA > scoreB) {
7192451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " > ";
7202451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
721b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsWithScorer " + a.configKey()
7222451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + a.visibility.rssi24
7232451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.rssi5
7242451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + a.visibility.num24
7252451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.num5 + ")"
726e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    + " sc=" + scoreA
7272451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + prefer + b.configKey()
7282451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + b.visibility.rssi24
7292451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.rssi5
7302451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + b.visibility.num24
7312451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.num5 + ")"
732e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    + " sc=" + scoreB
7332451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " -> " + Integer.toString(scoreB - scoreA));
7342451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
735c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
7362451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If scoreA > scoreB, the comparison is descending hence the return value is negative
7372451dbcc4f9641df188326215b204b798eb70c46vandwalle        return scoreB - scoreA;
7382451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
7392451dbcc4f9641df188326215b204b798eb70c46vandwalle
740f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    int compareWifiConfigurations(WifiConfiguration a, WifiConfiguration b) {
741f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
742f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        boolean linked = false;
743f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
744453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if ((a.linkedConfigurations != null) && (b.linkedConfigurations != null)
745453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (a.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)
746453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (b.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)) {
7472451dbcc4f9641df188326215b204b798eb70c46vandwalle            if ((a.linkedConfigurations.get(b.configKey(true)) != null)
7482451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && (b.linkedConfigurations.get(a.configKey(true)) != null)) {
749f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                linked = true;
750f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
751f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
752f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
753f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (a.ephemeral && b.ephemeral == false) {
754f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
755b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurations ephemeral and prefers " + b.configKey()
756453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + a.configKey());
757f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
758931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            return 1; // b is of higher priority - ascending
759f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
760f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (b.ephemeral && a.ephemeral == false) {
761f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
762b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurations ephemeral and prefers " + a.configKey()
763453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey());
764f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
765931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            return -1; // a is of higher priority - descending
766f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
767f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
7682451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply RSSI, in the range [-5, +5]
7692451dbcc4f9641df188326215b204b798eb70c46vandwalle        // after band adjustment, +n difference roughly corresponds to +10xn dBm
7702451dbcc4f9641df188326215b204b798eb70c46vandwalle        order = order + compareWifiConfigurationsRSSI(a, b, mCurrentConfigurationKey);
771f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
7722451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If the configurations are not linked, compare by user's choice, only a
7732451dbcc4f9641df188326215b204b798eb70c46vandwalle        // very high RSSI difference can then override the choice
7742451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (!linked) {
7752451dbcc4f9641df188326215b204b798eb70c46vandwalle            int choice;
776f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
7772451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = getConnectChoice(a, b);
7782451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice > 0) {
779931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of higher priority - descending
7802451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = order - choice;
781f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG) {
782b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers " + a.configKey()
783453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + " over " + b.configKey()
784b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " due to user choice of " + choice
785b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " order -> " + Integer.toString(order));
786f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
7872451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
7882451dbcc4f9641df188326215b204b798eb70c46vandwalle
7892451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = getConnectChoice(b, a);
7902451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice > 0) {
791931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of lower priority - ascending
7922451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = order + choice;
7934dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                if (VDBG) {
794b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers " + b.configKey() + " over "
795b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + a.configKey() + " due to user choice of " + choice
796b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " order ->" + Integer.toString(order));
797f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
798f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
799f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
800ede1310be531a84faa08f02c3fd243448dd936ddvandwalle
801f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order == 0) {
802931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // We don't know anything - pick the last seen i.e. K behavior
803931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // we should do this only for recently picked configurations
804f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (a.priority > b.priority) {
805931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of higher priority - descending
8062451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (VDBG) {
807b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers -1 " + a.configKey() + " over "
808453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + b.configKey() + " due to priority");
809f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
810f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
811f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                order = -1;
812f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else if (a.priority < b.priority) {
813931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of lower priority - ascending
8142451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (VDBG) {
815b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers +1 " + b.configKey() + " over "
816453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + a.configKey() + " due to priority");
817f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
8182451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = 1;
819f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
820f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
821f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
822f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String sorder = " == ";
823931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        if (order > 0) {
824f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " < ";
825931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        } else if (order < 0) {
826f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " > ";
827931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        }
828f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
8292451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
830b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("compareWifiConfigurations: " + a.configKey() + sorder
831453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    + b.configKey() + " order " + Integer.toString(order));
832f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
833f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
834f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
835f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
836f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
837c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    boolean isBadCandidate(int rssi5, int rssi24) {
838c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        return (rssi5 < -80 && rssi24 < -90);
839c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    }
840c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
841c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    int compareWifiConfigurationsTop(WifiConfiguration a, WifiConfiguration b) {
842c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        int scorerOrder = compareWifiConfigurationsWithScorer(a, b);
843c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        int order = compareWifiConfigurations(a, b);
844c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
845c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        if (scorerOrder * order < 0) {
846b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (VDBG) {
847b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    -> compareWifiConfigurationsTop: " +
848b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                        "scorer override " + scorerOrder + " " + order);
849b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
850c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // For debugging purpose, remember that an override happened
851c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // during that autojoin Attempt
852c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            didOverride = true;
853c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            a.numScorerOverride++;
854c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            b.numScorerOverride++;
855c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        }
856c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
857c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        if (scorerOrder != 0) {
858c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // If the scorer came up with a result then use the scorer's result, else use
859c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // the order provided by the base comparison function
860c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            order = scorerOrder;
861c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        }
862c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        return order;
863c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    }
864c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
8659f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle    public int rssiBoostFrom5GHzRssi(int rssi, String dbg) {
8660eebae7334d6129f7ca1344e4b20199794994358vandwalle        if (!mWifiConfigStore.enable5GHzPreference) {
8670eebae7334d6129f7ca1344e4b20199794994358vandwalle            return 0;
8680eebae7334d6129f7ca1344e4b20199794994358vandwalle        }
869e67ec726c07410073575473c0f50dc737629f5davandwalle        if (rssi
8700eebae7334d6129f7ca1344e4b20199794994358vandwalle                > mWifiConfigStore.bandPreferenceBoostThreshold5) {
871e67ec726c07410073575473c0f50dc737629f5davandwalle            // Boost by 2 dB for each point
872e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Start boosting at -65
873e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Boost by 20 if above -55
874e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Boost by 40 if abore -45
8750eebae7334d6129f7ca1344e4b20199794994358vandwalle            int boost = mWifiConfigStore.bandPreferenceBoostFactor5
8760eebae7334d6129f7ca1344e4b20199794994358vandwalle                    *(rssi - mWifiConfigStore.bandPreferenceBoostThreshold5);
877e67ec726c07410073575473c0f50dc737629f5davandwalle            if (boost > 50) {
878e67ec726c07410073575473c0f50dc737629f5davandwalle                // 50 dB boost is set so as to overcome the hysteresis of +20 plus a difference of
879e67ec726c07410073575473c0f50dc737629f5davandwalle                // 25 dB between 2.4 and 5GHz band. This allows jumping from 2.4 to 5GHz
880e67ec726c07410073575473c0f50dc737629f5davandwalle                // consistently
881e67ec726c07410073575473c0f50dc737629f5davandwalle                boost = 50;
882e67ec726c07410073575473c0f50dc737629f5davandwalle            }
8839f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            if (VDBG && dbg != null) {
884b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("        " + dbg + ":    rssi5 " + rssi + " boost " + boost);
8859f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            }
886e67ec726c07410073575473c0f50dc737629f5davandwalle            return boost;
887e67ec726c07410073575473c0f50dc737629f5davandwalle        }
888e67ec726c07410073575473c0f50dc737629f5davandwalle
889e67ec726c07410073575473c0f50dc737629f5davandwalle        if (rssi
8900eebae7334d6129f7ca1344e4b20199794994358vandwalle                < mWifiConfigStore.bandPreferencePenaltyThreshold5) {
8910eebae7334d6129f7ca1344e4b20199794994358vandwalle            // penalize if < -75
8920eebae7334d6129f7ca1344e4b20199794994358vandwalle            int boost = mWifiConfigStore.bandPreferencePenaltyFactor5
8930eebae7334d6129f7ca1344e4b20199794994358vandwalle                    *(rssi - mWifiConfigStore.bandPreferencePenaltyThreshold5);
8940eebae7334d6129f7ca1344e4b20199794994358vandwalle            return boost;
895e67ec726c07410073575473c0f50dc737629f5davandwalle        }
896e67ec726c07410073575473c0f50dc737629f5davandwalle        return 0;
897e67ec726c07410073575473c0f50dc737629f5davandwalle    }
898c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        /**
899e67ec726c07410073575473c0f50dc737629f5davandwalle         * attemptRoam() function implements the core of the same SSID switching algorithm
900e67ec726c07410073575473c0f50dc737629f5davandwalle         *
901e67ec726c07410073575473c0f50dc737629f5davandwalle         * Run thru all recent scan result of a WifiConfiguration and select the
902e67ec726c07410073575473c0f50dc737629f5davandwalle         * best one.
903c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle         */
904e67ec726c07410073575473c0f50dc737629f5davandwalle    public ScanResult attemptRoam(ScanResult a,
905e67ec726c07410073575473c0f50dc737629f5davandwalle                                  WifiConfiguration current, int age, String currentBSSID) {
906b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current == null) {
907b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
908b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam not associated");
909b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
910e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
9114dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
912b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current.scanResultCache == null) {
913b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
914b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam no scan cache");
915b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
916e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
9174dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
918b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle        if (current.scanResultCache.size() > 6) {
919b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
920c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptRoam scan cache size "
921c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + current.scanResultCache.size() + " --> bail");
922b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
923931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Implement same SSID roaming only for configurations
924c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            // that have less than 4 BSSIDs
925e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
9264dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
927b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
9282f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle        if (current.BSSID != null && !current.BSSID.equals("any")) {
929b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (DBG)   {
9302f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                logDbg("attemptRoam() BSSID is set "
9312f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        + current.BSSID + " -> bail");
932b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
933e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
9344dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
9354dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
936931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Determine which BSSID we want to associate to, taking account
937c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle        // relative strength of 5 and 2.4 GHz BSSIDs
9382451dbcc4f9641df188326215b204b798eb70c46vandwalle        long nowMs = System.currentTimeMillis();
9394dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
94097b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle        for (ScanResult b : current.scanResultCache.values()) {
94197b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int bRssiBoost5 = 0;
94297b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int aRssiBoost5 = 0;
94397b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int bRssiBoost = 0;
94497b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int aRssiBoost = 0;
945931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            if ((b.seen == 0) || (b.BSSID == null)
9460d616ef3bf635dff8722e064c0be842676390ed8vandwalle                    || ((nowMs - b.seen) > age)
947e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    || b.autoJoinStatus != ScanResult.ENABLED
948e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    || b.numIpConfigFailures > 8) {
9494dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
9503a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
9514dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
952931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Pick first one
9534dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (a == null) {
9544dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                a = b;
9554dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
9564dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
9574dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
958e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            if (b.numIpConfigFailures < (a.numIpConfigFailures - 1)) {
959e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                // Prefer a BSSID that doesn't have less number of Ip config failures
960e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("attemptRoam: "
961e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + b.BSSID + " rssi=" + b.level + " ipfail=" +b.numIpConfigFailures
962e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " freq=" + b.frequency
963e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " > "
964e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + a.BSSID + " rssi=" + a.level + " ipfail=" +a.numIpConfigFailures
965e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " freq=" + a.frequency);
966e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                a = b;
967e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                continue;
968e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            }
969e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle
9702451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Apply hysteresis: we favor the currentBSSID by giving it a boost
9717806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentBSSID != null && currentBSSID.equals(b.BSSID)) {
972931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Reduce the benefit of hysteresis if RSSI <= -75
9730eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (b.level <= mWifiConfigStore.bandPreferencePenaltyThreshold5) {
9740eebae7334d6129f7ca1344e4b20199794994358vandwalle                    bRssiBoost = mWifiConfigStore.associatedHysteresisLow;
975c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
9760eebae7334d6129f7ca1344e4b20199794994358vandwalle                    bRssiBoost = mWifiConfigStore.associatedHysteresisHigh;
977c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
9784dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
9797806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentBSSID != null && currentBSSID.equals(a.BSSID)) {
9800eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (a.level <= mWifiConfigStore.bandPreferencePenaltyThreshold5) {
981931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Reduce the benefit of hysteresis if RSSI <= -75
9820eebae7334d6129f7ca1344e4b20199794994358vandwalle                    aRssiBoost = mWifiConfigStore.associatedHysteresisLow;
983c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
9840eebae7334d6129f7ca1344e4b20199794994358vandwalle                    aRssiBoost = mWifiConfigStore.associatedHysteresisHigh;
985c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
9864dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
9872451dbcc4f9641df188326215b204b798eb70c46vandwalle
98897b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            // Favor 5GHz: give a boost to 5GHz BSSIDs, with a slightly progressive curve
9892451dbcc4f9641df188326215b204b798eb70c46vandwalle            //   Boost the BSSID if it is on 5GHz, above a threshold
9902451dbcc4f9641df188326215b204b798eb70c46vandwalle            //   But penalize it if it is on 5GHz and below threshold
99197b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //
99297b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   With he current threshold values, 5GHz network with RSSI above -55
99397b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   Are given a boost of 30DB which is enough to overcome the current BSSID
99497b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   hysteresis (+14) plus 2.4/5 GHz signal strength difference on most cases
9959f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            //
9969f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // The "current BSSID" Boost must be added to the BSSID's level so as to introduce\
9979f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // soem amount of hysteresis
998e67ec726c07410073575473c0f50dc737629f5davandwalle            if (b.is5GHz()) {
9999f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                bRssiBoost5 = rssiBoostFrom5GHzRssi(b.level + bRssiBoost, b.BSSID);
10004dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
1001e67ec726c07410073575473c0f50dc737629f5davandwalle            if (a.is5GHz()) {
10029f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                aRssiBoost5 = rssiBoostFrom5GHzRssi(a.level + aRssiBoost, a.BSSID);
10034dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
10044dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
10054dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (VDBG)  {
1006c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                String comp = " < ";
1007c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
1008c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    comp = " > ";
1009c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
10104dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                logDbg("attemptRoam: "
1011c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + b.BSSID + " rssi=" + b.level + " boost=" + Integer.toString(bRssiBoost)
101297b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                        + "/" + Integer.toString(bRssiBoost5) + " freq=" + b.frequency
101397b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                        + comp
1014c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + a.BSSID + " rssi=" + a.level + " boost=" + Integer.toString(aRssiBoost)
1015c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + "/" + Integer.toString(aRssiBoost5) + " freq=" + a.frequency);
1016c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            }
1017c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle
10182451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Compare the RSSIs after applying the hysteresis boost and the 5GHz
10192451dbcc4f9641df188326215b204b798eb70c46vandwalle            // boost if applicable
1020c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
1021931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // b is the better BSSID
1022c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                a = b;
10234dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
10244dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
10253a2a3d226881cce8a4e511302231d843b0def303vandwalle        if (a != null) {
10263a2a3d226881cce8a4e511302231d843b0def303vandwalle            if (VDBG)  {
10277806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                StringBuilder sb = new StringBuilder();
1028e67ec726c07410073575473c0f50dc737629f5davandwalle                sb.append("attemptRoam: " + current.configKey() +
1029e67ec726c07410073575473c0f50dc737629f5davandwalle                        " Found " + a.BSSID + " rssi=" + a.level + " freq=" + a.frequency);
10307806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                if (currentBSSID != null) {
10317806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                    sb.append(" Current: " + currentBSSID);
10327806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                }
10337806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                sb.append("\n");
10347806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                logDbg(sb.toString());
10353a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
10364dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
10373a2a3d226881cce8a4e511302231d843b0def303vandwalle        return a;
10384dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    }
10394dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1040931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
10412451dbcc4f9641df188326215b204b798eb70c46vandwalle     * getNetworkScore()
10422451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
10432451dbcc4f9641df188326215b204b798eb70c46vandwalle     * if scorer is present, get the network score of a WifiConfiguration
10442451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
10452451dbcc4f9641df188326215b204b798eb70c46vandwalle     * Note: this should be merge with setVisibility
10462451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
10472451dbcc4f9641df188326215b204b798eb70c46vandwalle     * @param config
10482451dbcc4f9641df188326215b204b798eb70c46vandwalle     * @return score
10492451dbcc4f9641df188326215b204b798eb70c46vandwalle     */
105081c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson    int getConfigNetworkScore(WifiConfiguration config, int age, boolean isActive) {
10512451dbcc4f9641df188326215b204b798eb70c46vandwalle
10522451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (mNetworkScoreCache == null) {
1053e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (VDBG) {
1054b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("       getConfigNetworkScore for " + config.configKey()
1055e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + "  -> no scorer, hence no scores");
1056e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
10571db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            return WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
10581db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        }
10591db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        if (config.scanResultCache == null) {
1060e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (VDBG) {
1061b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("       getConfigNetworkScore for " + config.configKey()
1062e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " -> no scan cache");
1063e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
10641db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            return WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
10652451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
10662451dbcc4f9641df188326215b204b798eb70c46vandwalle
10672451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Get current date
10682451dbcc4f9641df188326215b204b798eb70c46vandwalle        long nowMs = System.currentTimeMillis();
10692451dbcc4f9641df188326215b204b798eb70c46vandwalle
10701db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        int startScore = -10000;
10711db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle
10722451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Run thru all cached scan results
10731db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        for (ScanResult result : config.scanResultCache.values()) {
10742451dbcc4f9641df188326215b204b798eb70c46vandwalle            if ((nowMs - result.seen) < age) {
107581c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                int sc = mNetworkScoreCache.getNetworkScore(result, isActive);
10761db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle                if (sc > startScore) {
10771db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle                    startScore = sc;
10782451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
10792451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
10802451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
10811db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        if (startScore == -10000) {
10821db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            startScore = WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
10831db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        }
1084e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle        if (VDBG) {
1085e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (startScore == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
1086b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    getConfigNetworkScore for " + config.configKey()
1087e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " -> no available score");
1088e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            } else {
1089b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    getConfigNetworkScore for " + config.configKey()
109081c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                        + " isActive=" + isActive
1091e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " score = " + Integer.toString(startScore));
1092e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
1093e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle        }
1094e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle
10951db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        return startScore;
10962451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
10972451dbcc4f9641df188326215b204b798eb70c46vandwalle
10982451dbcc4f9641df188326215b204b798eb70c46vandwalle    /**
10998639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson     * Set whether connections to untrusted connections are allowed.
11008639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson     */
11018639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    void setAllowUntrustedConnections(boolean allow) {
11028639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        boolean changed = mAllowUntrustedConnections != allow;
11038639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        mAllowUntrustedConnections = allow;
11048639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        if (changed) {
1105005c1ef113192f898499a407dd266393a8d6b076vandwalle            // Trigger a scan so as to reattempt autojoin
1106005c1ef113192f898499a407dd266393a8d6b076vandwalle            mWifiStateMachine.startScanForUntrustedSettingChange();
11078639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        }
11088639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    }
11098639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
11108639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    private boolean isOpenNetwork(ScanResult result) {
11118639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        return !result.capabilities.contains("WEP") &&
11128639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                !result.capabilities.contains("PSK") &&
11138639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                !result.capabilities.contains("EAP");
11148639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    }
11158639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
11168639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    /**
1117931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * attemptAutoJoin() function implements the core of the a network switching algorithm
111868fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle     * Return false if no acceptable networks were found.
1119931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
112068fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle    boolean attemptAutoJoin() {
112168fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle        boolean found = false;
1122c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        didOverride = false;
11231ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        didBailDueToWeakRssi = false;
1124b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        int networkSwitchType = AUTO_JOIN_IDLE;
11254dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
11268c9088d11880553458f09377cc60d6eb7e66747bvandwalle        String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
11278c9088d11880553458f09377cc60d6eb7e66747bvandwalle
1128931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Reset the currentConfiguration Key, and set it only if WifiStateMachine and
1129453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        // supplicant agree
1130453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        mCurrentConfigurationKey = null;
1131453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        WifiConfiguration currentConfiguration = mWifiStateMachine.getCurrentWifiConfiguration();
1132453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
1133f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration candidate = null;
1134f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1135931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Obtain the subset of recently seen networks
113627355a942653264388e909a4276196ee63e57811vandwalle        List<WifiConfiguration> list = mWifiConfigStore.getRecentConfiguredNetworks(3000, false);
1137f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (list == null) {
11382f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            if (VDBG)  logDbg("attemptAutoJoin nothing known=" +
11392f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    mWifiConfigStore.getconfiguredNetworkSize());
114068fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle            return false;
1141f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1142f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1143931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Find the currently connected network: ask the supplicant directly
114499d385e3b4d34841d6efcfd7cc9bf1d5ae25de14vandwalle        String val = mWifiNative.status(true);
1145f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String status[] = val.split("\\r?\\n");
1146f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
1147f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("attemptAutoJoin() status=" + val + " split="
1148f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(status.length));
1149f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1150f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1151b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        int supplicantNetId = -1;
1152f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (String key : status) {
1153f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (key.regionMatches(0, "id=", 0, 3)) {
1154f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int idx = 3;
1155b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                supplicantNetId = 0;
1156f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                while (idx < key.length()) {
1157f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    char c = key.charAt(idx);
1158f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1159f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if ((c >= 0x30) && (c <= 0x39)) {
1160b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        supplicantNetId *= 10;
1161b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        supplicantNetId += c - 0x30;
1162f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        idx++;
1163f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    } else {
1164f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        break;
1165f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
1166f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
116756d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle            } else if (key.contains("wpa_state=ASSOCIATING")
116856d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                    || key.contains("wpa_state=ASSOCIATED")
116956d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                    || key.contains("wpa_state=FOUR_WAY_HANDSHAKE")
117056d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                    || key.contains("wpa_state=GROUP_KEY_HANDSHAKE")) {
117156d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                if (DBG) {
117256d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                    logDbg("attemptAutoJoin: bail out due to sup state " + key);
117356d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                }
117456d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // After WifiStateMachine ask the supplicant to associate or reconnect
117556d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // we might still obtain scan results from supplicant
117656d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // however the supplicant state in the mWifiInfo and supplicant state tracker
117756d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // are updated when we get the supplicant state change message which can be
117856d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // processed after the SCAN_RESULT message, so at this point the framework doesn't
117956d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // know that supplicant is ASSOCIATING.
118056d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // A good fix for this race condition would be for the WifiStateMachine to add
118156d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // a new transient state where it expects to get the supplicant message indicating
118256d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // that it started the association process and within which critical operations
118356d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // like autojoin should be deleted.
118456d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle
118556d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // This transient state would remove the need for the roam Wathchdog which
118656d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // basically does that.
118756d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle
118856d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // At the moment, we just query the supplicant state synchronously with the
118956d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // mWifiNative.status() command, which allow us to know that
119056d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // supplicant has started association process, even though we didnt yet get the
119156d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // SUPPLICANT_STATE_CHANGE message.
119268fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                return false;
1193f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1194f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1195ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (DBG) {
11967806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            String conf = "";
1197b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String last = "";
11987806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentConfiguration != null) {
1199e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                conf = " current=" + currentConfiguration.configKey();
1200b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1201b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (lastSelectedConfiguration != null) {
12022f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                last = " last=" + lastSelectedConfiguration;
12037806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            }
1204ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            logDbg("attemptAutoJoin() num recent config " + Integer.toString(list.size())
1205b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + conf + last
1206b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + " ---> suppNetId=" + Integer.toString(supplicantNetId));
1207ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
1208f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1209453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if (currentConfiguration != null) {
12102451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (supplicantNetId != currentConfiguration.networkId
1211005c1ef113192f898499a407dd266393a8d6b076vandwalle                    // https://b.corp.google.com/issue?id=16484607
1212005c1ef113192f898499a407dd266393a8d6b076vandwalle                    // mark this condition as an error only if the mismatched networkId are valid
12132451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID
12142451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && currentConfiguration.networkId != WifiConfiguration.INVALID_NETWORK_ID) {
1215453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("attemptAutoJoin() ERROR wpa_supplicant out of sync nid="
1216b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        + Integer.toString(supplicantNetId) + " WifiStateMachine="
1217453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + Integer.toString(currentConfiguration.networkId));
1218b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                mWifiStateMachine.disconnectCommand();
121968fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                return false;
12208639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson            } else if (currentConfiguration.ephemeral && (!mAllowUntrustedConnections ||
12218639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                    !mNetworkScoreCache.isScoredNetwork(currentConfiguration.lastSeen()))) {
12228639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                // The current connection is untrusted (the framework added it), but we're either
12238639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                // no longer allowed to connect to such networks, or the score has been nullified
12248639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                // since we connected. Drop the current connection and perform the rest of autojoin.
12258639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                logDbg("attemptAutoJoin() disconnecting from unwanted ephemeral network");
12268639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                mWifiStateMachine.disconnectCommand();
122768fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                return false;
1228453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            } else {
1229453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                mCurrentConfigurationKey = currentConfiguration.configKey();
1230453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            }
12318c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle        } else {
12328c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle            if (supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID) {
12338c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                // Maybe in the process of associating, skip this attempt
123468fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                return false;
12358c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle            }
1236453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        }
1237453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
1238b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        int currentNetId = -1;
1239b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentConfiguration != null) {
1240931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // If we are associated to a configuration, it will
1241b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            // be compared thru the compareNetwork function
1242b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            currentNetId = currentConfiguration.networkId;
1243b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
1244b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle
1245931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1246931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * Run thru all visible configurations without looking at the one we
1247c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle         * are currently associated to
12484dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle         * select Best Network candidate from known WifiConfigurations
1249931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1250f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (WifiConfiguration config : list) {
1251e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            if (config.SSID == null) {
1252b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                continue;
1253e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            }
1254e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
125527355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
125627355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
1257931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Avoid networks disabled because of AUTH failure altogether
1258ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
1259ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                    logDbg("attemptAutoJoin skip candidate due to auto join status "
1260ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + Integer.toString(config.autoJoinStatus) + " key "
1261e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                            + config.configKey(true)
1262e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    + " reason " + config.disableReason);
1263ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
1264f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1265f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1266f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1267931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to un-blacklist based on elapsed time
126827355a942653264388e909a4276196ee63e57811vandwalle            if (config.blackListTimestamp > 0) {
126927355a942653264388e909a4276196ee63e57811vandwalle                long now = System.currentTimeMillis();
127027355a942653264388e909a4276196ee63e57811vandwalle                if (now < config.blackListTimestamp) {
1271931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    /**
1272931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * looks like there was a change in the system clock since we black listed, and
1273931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * timestamp is not meaningful anymore, hence lose it.
1274931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * this event should be rare enough so that we still want to lose the black list
12752451dbcc4f9641df188326215b204b798eb70c46vandwalle                     */
127627355a942653264388e909a4276196ee63e57811vandwalle                    config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
127727355a942653264388e909a4276196ee63e57811vandwalle                } else {
12784dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    if ((now - config.blackListTimestamp) > loseBlackListHardMilli) {
1279931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Reenable it after 18 hours, i.e. next day
128027355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
12814dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    } else if ((now - config.blackListTimestamp) > loseBlackListSoftMilli) {
1282931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Lose blacklisting due to bad link
128327355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(config.autoJoinStatus - 8);
128427355a942653264388e909a4276196ee63e57811vandwalle                    }
128527355a942653264388e909a4276196ee63e57811vandwalle                }
128627355a942653264388e909a4276196ee63e57811vandwalle            }
128727355a942653264388e909a4276196ee63e57811vandwalle
1288931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to unblacklist based on good visibility
12898c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle            if (config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Soft
12908c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    && config.visibility.rssi24
12918c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    < mWifiConfigStore.thresholdUnblacklistThreshold24Soft) {
129227355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
1293c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    logDbg("attemptAutoJoin do not unblacklist due to low visibility "
12944dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.autoJoinStatus
12954dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " key " + config.configKey(true)
12964dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " rssi=(" + config.visibility.rssi24
12974dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.rssi5
12984dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
12994dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
130027355a942653264388e909a4276196ee63e57811vandwalle                }
13018c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle            } else if (config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Hard
13028c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    && config.visibility.rssi24
13038c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    < mWifiConfigStore.thresholdUnblacklistThreshold24Hard) {
1304931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // If the network is simply temporary disabled, don't allow reconnect until
1305931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // RSSI becomes good enough
130627355a942653264388e909a4276196ee63e57811vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 1);
130727355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
130827355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped soft -> status="
130927355a942653264388e909a4276196ee63e57811vandwalle                            + config.autoJoinStatus
1310b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " " + config.configKey(true) + " rssi=("
13114dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
13124dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
13134dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
131427355a942653264388e909a4276196ee63e57811vandwalle                }
131527355a942653264388e909a4276196ee63e57811vandwalle            } else {
1316c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 3);
131727355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
131827355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped hard -> status="
131927355a942653264388e909a4276196ee63e57811vandwalle                            + config.autoJoinStatus
1320b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " " + config.configKey(true) + " rssi=("
13214dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
13224dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
13234dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
132427355a942653264388e909a4276196ee63e57811vandwalle                }
132527355a942653264388e909a4276196ee63e57811vandwalle            }
132627355a942653264388e909a4276196ee63e57811vandwalle
132727355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
132827355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED) {
1329931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Network is blacklisted, skip
13304dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                if (DBG) {
13314dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    logDbg("attemptAutoJoin skip blacklisted -> status="
13324dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.autoJoinStatus
1333b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " " + config.configKey(true) + " rssi=("
13344dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
13354dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
13364dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
13374dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                }
133827355a942653264388e909a4276196ee63e57811vandwalle                continue;
133927355a942653264388e909a4276196ee63e57811vandwalle            }
1340f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (config.networkId == currentNetId) {
1341ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
134221bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    logDbg("attemptAutoJoin skip current candidate  "
134321bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                            + Integer.toString(currentNetId)
1344ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + " key " + config.configKey(true));
1345ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
1346f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1347f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1348f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
13490eebae7334d6129f7ca1344e4b20199794994358vandwalle            boolean isLastSelected = false;
13500eebae7334d6129f7ca1344e4b20199794994358vandwalle            if (lastSelectedConfiguration != null &&
13510eebae7334d6129f7ca1344e4b20199794994358vandwalle                    config.configKey().equals(lastSelectedConfiguration)) {
13520eebae7334d6129f7ca1344e4b20199794994358vandwalle                isLastSelected = true;
13530eebae7334d6129f7ca1344e4b20199794994358vandwalle            }
13540eebae7334d6129f7ca1344e4b20199794994358vandwalle
13550eebae7334d6129f7ca1344e4b20199794994358vandwalle            if (config.visibility == null) {
13560eebae7334d6129f7ca1344e4b20199794994358vandwalle                continue;
13570eebae7334d6129f7ca1344e4b20199794994358vandwalle            }
13581ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            int boost = config.autoJoinUseAggressiveJoinAttemptThreshold + weakRssiBailCount;
13590eebae7334d6129f7ca1344e4b20199794994358vandwalle            if ((config.visibility.rssi5 + boost)
13600eebae7334d6129f7ca1344e4b20199794994358vandwalle                        < mWifiConfigStore.thresholdInitialAutoJoinAttemptMin5RSSI
13610eebae7334d6129f7ca1344e4b20199794994358vandwalle                        && (config.visibility.rssi24 + boost)
13620eebae7334d6129f7ca1344e4b20199794994358vandwalle                        < mWifiConfigStore.thresholdInitialAutoJoinAttemptMin24RSSI) {
13630eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (DBG) {
13640eebae7334d6129f7ca1344e4b20199794994358vandwalle                    logDbg("attemptAutoJoin skip due to low visibility -> status="
13650eebae7334d6129f7ca1344e4b20199794994358vandwalle                            + config.autoJoinStatus
13660eebae7334d6129f7ca1344e4b20199794994358vandwalle                            + " key " + config.configKey(true) + " rssi="
13670eebae7334d6129f7ca1344e4b20199794994358vandwalle                            + config.visibility.rssi24 + ", " + config.visibility.rssi5
13680eebae7334d6129f7ca1344e4b20199794994358vandwalle                            + " num=" + config.visibility.num24
13690eebae7334d6129f7ca1344e4b20199794994358vandwalle                            + ", " + config.visibility.num5);
13700eebae7334d6129f7ca1344e4b20199794994358vandwalle                }
13710eebae7334d6129f7ca1344e4b20199794994358vandwalle
1372c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // Don't try to autojoin a network that is too far but
1373c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // If that configuration is a user's choice however, try anyway
13740eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (!isLastSelected) {
13750eebae7334d6129f7ca1344e4b20199794994358vandwalle                    config.autoJoinBailedDueToLowRssi = true;
13761ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                    didBailDueToWeakRssi = true;
13778c9088d11880553458f09377cc60d6eb7e66747bvandwalle                    continue;
13780eebae7334d6129f7ca1344e4b20199794994358vandwalle                } else {
13790eebae7334d6129f7ca1344e4b20199794994358vandwalle                    // Next time, try to be a bit more aggressive in auto-joining
13800eebae7334d6129f7ca1344e4b20199794994358vandwalle                    if (config.autoJoinUseAggressiveJoinAttemptThreshold
1381dd0c558776fcfba3f754bb0cd6533f2c9c23ec1evandwalle                            < WifiConfiguration.MAX_INITIAL_AUTO_JOIN_RSSI_BOOST
1382dd0c558776fcfba3f754bb0cd6533f2c9c23ec1evandwalle                            && config.autoJoinBailedDueToLowRssi) {
1383dd0c558776fcfba3f754bb0cd6533f2c9c23ec1evandwalle                        config.autoJoinUseAggressiveJoinAttemptThreshold += 4;
13844dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    }
13858c9088d11880553458f09377cc60d6eb7e66747bvandwalle                }
13860eebae7334d6129f7ca1344e4b20199794994358vandwalle            }
1387d30127db46224e45554f8964209221bba8ad41d9vandwalle            if (config.numNoInternetAccessReports > 0
1388d30127db46224e45554f8964209221bba8ad41d9vandwalle                    && !isLastSelected
1389d30127db46224e45554f8964209221bba8ad41d9vandwalle                    && !config.validatedInternetAccess) {
1390d30127db46224e45554f8964209221bba8ad41d9vandwalle                // Avoid autoJoining this network because last time we used it, it didn't
1391d30127db46224e45554f8964209221bba8ad41d9vandwalle                // have internet access, and we never manage to validate internet access on this
1392d30127db46224e45554f8964209221bba8ad41d9vandwalle                // network configuration
13930eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (DBG) {
1394d30127db46224e45554f8964209221bba8ad41d9vandwalle                    logDbg("attemptAutoJoin skip candidate due to no InternetAccess  "
1395d30127db46224e45554f8964209221bba8ad41d9vandwalle                            + config.configKey(true)
1396d30127db46224e45554f8964209221bba8ad41d9vandwalle                            + " num reports " + config.numNoInternetAccessReports);
13979f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                }
13980eebae7334d6129f7ca1344e4b20199794994358vandwalle                continue;
13998c9088d11880553458f09377cc60d6eb7e66747bvandwalle            }
14008c9088d11880553458f09377cc60d6eb7e66747bvandwalle
1401ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            if (DBG) {
1402e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                String cur = "";
1403e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                if (candidate != null) {
1404e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    cur = " current candidate " + candidate.configKey();
1405e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                }
1406e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("attemptAutoJoin trying id="
1407c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + Integer.toString(config.networkId) + " "
1408b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                        + config.configKey(true)
1409e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " status=" + config.autoJoinStatus
1410e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + cur);
1411ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            }
1412f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1413f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate == null) {
1414f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                candidate = config;
1415f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
1416f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)  {
1417453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("attemptAutoJoin will compare candidate  " + candidate.configKey()
14184dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " with " + config.configKey());
1419f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1420c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                int order = compareWifiConfigurationsTop(candidate, config);
14212451dbcc4f9641df188326215b204b798eb70c46vandwalle
14222451dbcc4f9641df188326215b204b798eb70c46vandwalle                // The lastSelectedConfiguration is the configuration the user has manually selected
1423c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // thru WifiPicker, or that a 3rd party app asked us to connect to via the
14242451dbcc4f9641df188326215b204b798eb70c46vandwalle                // enableNetwork with disableOthers=true WifiManager API
14252451dbcc4f9641df188326215b204b798eb70c46vandwalle                // As this is a direct user choice, we strongly prefer this configuration,
14262451dbcc4f9641df188326215b204b798eb70c46vandwalle                // hence give +/-100
14272451dbcc4f9641df188326215b204b798eb70c46vandwalle                if ((lastSelectedConfiguration != null)
14282451dbcc4f9641df188326215b204b798eb70c46vandwalle                        && candidate.configKey().equals(lastSelectedConfiguration)) {
14292451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // candidate is the last selected configuration,
14302451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // so keep it above connect choices (+/-60) and
14312451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // above RSSI/scorer based selection of linked configuration (+/- 50)
14322451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // by reducing order by -100
14332451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = order - 100;
14342451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (VDBG)   {
14352f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        logDbg("     ...and prefers -100 " + candidate.configKey()
14362451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " over " + config.configKey()
14372451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " because it is the last selected -> "
14382451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + Integer.toString(order));
14392451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
14402451dbcc4f9641df188326215b204b798eb70c46vandwalle                } else if ((lastSelectedConfiguration != null)
14412451dbcc4f9641df188326215b204b798eb70c46vandwalle                        && config.configKey().equals(lastSelectedConfiguration)) {
14422451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // config is the last selected configuration,
14432451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // so keep it above connect choices (+/-60) and
14442451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // above RSSI/scorer based selection of linked configuration (+/- 50)
14452451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // by increasing order by +100
14462451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = order + 100;
14472451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (VDBG)   {
14482f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        logDbg("     ...and prefers +100 " + config.configKey()
14492451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " over " + candidate.configKey()
14502451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " because it is the last selected -> "
14512451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + Integer.toString(order));
14522451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
14532451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
14542451dbcc4f9641df188326215b204b798eb70c46vandwalle
1455f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (order > 0) {
1456931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Ascending : candidate < config
1457f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    candidate = config;
1458f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1459f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1460f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1461f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
14622451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Now, go thru scan result to try finding a better untrusted network
14638639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        // TODO: Consider only running this when we can actually connect to these networks. For now,
14648639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        // this is useful for debugging.
1465f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (mNetworkScoreCache != null) {
1466f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi5 = WifiConfiguration.INVALID_RSSI;
1467f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi24 = WifiConfiguration.INVALID_RSSI;
1468f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate != null) {
1469f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi5 = candidate.visibility.rssi5;
1470f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi24 = candidate.visibility.rssi24;
1471f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1472f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1473931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Get current date
14742451dbcc4f9641df188326215b204b798eb70c46vandwalle            long nowMs = System.currentTimeMillis();
1475c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            int currentScore = -10000;
1476c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // The untrusted network with highest score
1477c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            ScanResult untrustedCandidate = null;
14782451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Look for untrusted scored network only if the current candidate is bad
1479c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (isBadCandidate(rssi24, rssi5)) {
1480f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                for (ScanResult result : scanResultCache.values()) {
1481c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // We look only at untrusted networks with a valid SSID
1482c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // A trusted result would have been looked at thru it's Wificonfiguration
14838639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                    if (TextUtils.isEmpty(result.SSID) || !result.untrusted ||
14848639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                            !isOpenNetwork(result)) {
1485c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        continue;
1486c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    }
14872451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if ((nowMs - result.seen) < 3000) {
1488c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        // Increment usage count for the network
1489c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        mWifiConnectionStatistics.incrementOrAddUntrusted(result.SSID, 0, 1);
1490c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
149181c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                        boolean isActiveNetwork = lastUntrustedBSSID != null
149281c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                                && result.BSSID.equals(lastUntrustedBSSID);
149381c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                        int score = mNetworkScoreCache.getNetworkScore(result, isActiveNetwork);
1494c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        if (score != WifiNetworkScoreCache.INVALID_NETWORK_SCORE
1495c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                && score > currentScore) {
1496c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            // Highest score: Select this candidate
1497c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            currentScore = score;
1498c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            untrustedCandidate = result;
1499c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            if (VDBG) {
1500c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                logDbg("AutoJoinController: found untrusted candidate "
1501c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                        + result.SSID
1502c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                + " RSSI=" + result.level
1503c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                + " freq=" + result.frequency
1504c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                + " score=" + score);
1505c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            }
1506f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        }
1507f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
1508f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1509f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1510c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (untrustedCandidate != null) {
1511c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                if (lastUntrustedBSSID == null
1512c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        || !untrustedCandidate.SSID.equals(lastUntrustedBSSID)) {
1513c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // We found a new candidate that we are going to connect to, then
1514c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // increase its connection count
15158c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    mWifiConnectionStatistics.
15168c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                            incrementOrAddUntrusted(untrustedCandidate.SSID, 1, 0);
1517c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // Remember which SSID we are connecting to
1518c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    lastUntrustedBSSID = untrustedCandidate.SSID;
1519c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                }
15208639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
15218639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                // At this point, we have an untrusted network candidate.
15228639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                // Create the new ephemeral configuration and see if we should switch over
15238639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                if (mAllowUntrustedConnections) {
15248639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                    candidate =
15258639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                            mWifiConfigStore.wifiConfigurationFromScanResult(untrustedCandidate);
15268639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                    candidate.allowedKeyManagement.set(KeyMgmt.NONE);
15278639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                    candidate.ephemeral = true;
15288639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                }
1529c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            }
1530c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        }
1531b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
15321ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        long lastUnwanted =
15331ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                System.currentTimeMillis()
15341ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                        - mWifiConfigStore.lastUnwantedNetworkDisconnectTimestamp;
15351ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        if (candidate == null
15361ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && lastSelectedConfiguration == null
15371ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && currentConfiguration == null
15381ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && didBailDueToWeakRssi
15391ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && (mWifiConfigStore.lastUnwantedNetworkDisconnectTimestamp == 0
15401ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                    || lastUnwanted > (1000 * 60 * 60 * 24 * 7))
15411ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                ) {
15421ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // We are bailing out of autojoin although we are seeing a weak configuration, and
15431ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - we didn't find another valid candidate
15441ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - we are not connected
15451ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - without a user network selection choice
15461ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - ConnectivityService has not triggered an unwanted network disconnect
15471ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            //       on this device for a week (hence most likely there is no SIM card or cellular)
15481ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // If all those conditions are met, then boost the RSSI of the weak networks
15491ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // that we are seeing so as we will eventually pick one
15501ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            if (weakRssiBailCount < 10)
15511ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                weakRssiBailCount += 1;
15521ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        } else {
15531ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            if (weakRssiBailCount > 0)
15541ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                weakRssiBailCount -= 1;
15551ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        }
15561ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle
1557931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1558931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         *  If candidate is found, check the state of the connection so as
1559931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         *  to decide if we should be acting on this candidate and switching over
1560931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1561e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        int networkDelta = compareNetwork(candidate, lastSelectedConfiguration);
1562b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (DBG && candidate != null) {
1563b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String doSwitch = "";
1564b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String current = "";
1565b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (networkDelta < 0) {
1566b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                doSwitch = " -> not switching";
1567b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1568b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (currentConfiguration != null) {
15692f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                current = " with current " + currentConfiguration.configKey();
1570b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1571b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("attemptAutoJoin networkSwitching candidate "
1572b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                    + candidate.configKey()
1573b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + current
1574c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    + " linked=" + (currentConfiguration != null
1575b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            && currentConfiguration.isLinked(candidate))
1576b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + " : delta="
1577b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + Integer.toString(networkDelta) + " "
1578b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + doSwitch);
1579b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
15804dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1581931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1582931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * Ask WifiStateMachine permission to switch :
1583931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * if user is currently streaming voice traffic,
1584931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * then we should not be allowed to switch regardless of the delta
1585931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1586b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (mWifiStateMachine.shouldSwitchNetwork(networkDelta)) {
1587b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (mStaStaSupported) {
1588b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("mStaStaSupported --> error do nothing now ");
1589b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            } else {
1590b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (currentConfiguration != null && currentConfiguration.isLinked(candidate)) {
1591b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_EXTENDED_ROAMING;
1592b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                } else {
1593b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_OUT_OF_NETWORK_ROAMING;
1594b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1595b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1596b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto connect with netId "
1597b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(candidate.networkId)
1598b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " to " + candidate.configKey());
1599b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
16002451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (didOverride) {
16012451dbcc4f9641df188326215b204b798eb70c46vandwalle                    candidate.numScorerOverrideAndSwitchedNetwork++;
16022451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
1603c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                candidate.numAssociation++;
1604e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                mWifiConnectionStatistics.numAutoJoinAttempt++;
16059f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
16062f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                if (candidate.BSSID == null || candidate.BSSID.equals("any")) {
16072f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // First step we selected the configuration we want to connect to
16082f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // Second step: Look for the best Scan result for this configuration
16092f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // TODO this algorithm should really be done in one step
16102f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    String currentBSSID = mWifiStateMachine.getCurrentBSSID();
16112f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    ScanResult roamCandidate = attemptRoam(null, candidate, 3000, null);
16122f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    if (roamCandidate != null && currentBSSID != null
16132f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                            && currentBSSID.equals(roamCandidate.BSSID)) {
16142f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // Sanity, we were already asociated to that candidate
16152f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        roamCandidate = null;
16162f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    }
16172f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    if (roamCandidate != null && roamCandidate.is5GHz()) {
16182f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // If the configuration hasn't a default BSSID selected, and the best
16192f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // candidate is 5GHZ, then select this candidate so as WifiStateMachine and
16202f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // supplicant will pick it first
16212f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        candidate.autoJoinBSSID = roamCandidate.BSSID;
16222f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        if (VDBG) {
16232f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                            logDbg("AutoJoinController: lock to 5GHz "
16242f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                                    + candidate.autoJoinBSSID
16252f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                                    + " RSSI=" + roamCandidate.level
16262f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                                    + " freq=" + roamCandidate.frequency);
16272f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        }
1628448c9536a302c58a79e271b1721c08b8882f800evandwalle                    } else {
1629448c9536a302c58a79e271b1721c08b8882f800evandwalle                        // We couldnt find a roam candidate
1630448c9536a302c58a79e271b1721c08b8882f800evandwalle                        candidate.autoJoinBSSID = "any";
16319f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    }
16329f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                }
1633448c9536a302c58a79e271b1721c08b8882f800evandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT,
1634448c9536a302c58a79e271b1721c08b8882f800evandwalle                            candidate.networkId, networkSwitchType, candidate);
163568fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                found = true;
16364dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
1637b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
16384dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1639b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (networkSwitchType == AUTO_JOIN_IDLE) {
1640e67ec726c07410073575473c0f50dc737629f5davandwalle            String currentBSSID = mWifiStateMachine.getCurrentBSSID();
1641931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Attempt same WifiConfiguration roaming
1642e67ec726c07410073575473c0f50dc737629f5davandwalle            ScanResult roamCandidate = attemptRoam(null, currentConfiguration, 3000,
1643e67ec726c07410073575473c0f50dc737629f5davandwalle                    currentBSSID);
1644e67ec726c07410073575473c0f50dc737629f5davandwalle            /**
1645e67ec726c07410073575473c0f50dc737629f5davandwalle             *  TODO: (post L initial release)
1646e67ec726c07410073575473c0f50dc737629f5davandwalle             *  consider handling linked configurations roaming (i.e. extended Roaming)
1647e67ec726c07410073575473c0f50dc737629f5davandwalle             *  thru the attemptRoam function which makes use of the RSSI roaming threshold.
1648e67ec726c07410073575473c0f50dc737629f5davandwalle             *  At the moment, extended roaming is only handled thru the attemptAutoJoin()
1649e67ec726c07410073575473c0f50dc737629f5davandwalle             *  function which compare configurations.
1650e67ec726c07410073575473c0f50dc737629f5davandwalle             *
1651e67ec726c07410073575473c0f50dc737629f5davandwalle             *  The advantage of making use of attemptRoam function is that this function
1652e67ec726c07410073575473c0f50dc737629f5davandwalle             *  will looks at all the BSSID of each configurations, instead of only looking
1653e67ec726c07410073575473c0f50dc737629f5davandwalle             *  at WifiConfiguration.visibility which keeps trackonly of the RSSI/band of the
1654e67ec726c07410073575473c0f50dc737629f5davandwalle             *  two highest BSSIDs.
1655e67ec726c07410073575473c0f50dc737629f5davandwalle             */
1656e67ec726c07410073575473c0f50dc737629f5davandwalle            // Attempt linked WifiConfiguration roaming
1657e67ec726c07410073575473c0f50dc737629f5davandwalle            /* if (currentConfiguration != null
1658e67ec726c07410073575473c0f50dc737629f5davandwalle                    && currentConfiguration.linkedConfigurations != null) {
1659e67ec726c07410073575473c0f50dc737629f5davandwalle                for (String key : currentConfiguration.linkedConfigurations.keySet()) {
1660e67ec726c07410073575473c0f50dc737629f5davandwalle                    WifiConfiguration link = mWifiConfigStore.getWifiConfiguration(key);
1661e67ec726c07410073575473c0f50dc737629f5davandwalle                    if (link != null) {
1662e67ec726c07410073575473c0f50dc737629f5davandwalle                        roamCandidate = attemptRoam(roamCandidate, link, 3000,
1663e67ec726c07410073575473c0f50dc737629f5davandwalle                                currentBSSID);
1664e67ec726c07410073575473c0f50dc737629f5davandwalle                    }
1665e67ec726c07410073575473c0f50dc737629f5davandwalle                }
1666e67ec726c07410073575473c0f50dc737629f5davandwalle            }*/
1667e67ec726c07410073575473c0f50dc737629f5davandwalle            if (roamCandidate != null && currentBSSID != null
1668e67ec726c07410073575473c0f50dc737629f5davandwalle                    && currentBSSID.equals(roamCandidate.BSSID)) {
1669e67ec726c07410073575473c0f50dc737629f5davandwalle                roamCandidate = null;
1670e67ec726c07410073575473c0f50dc737629f5davandwalle            }
16712f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            if (roamCandidate != null && mWifiStateMachine.shouldSwitchNetwork(999)) {
1672b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1673b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto roam with netId "
1674b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(currentConfiguration.networkId)
1675b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " " + currentConfiguration.configKey() + " to BSSID="
1676b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + roamCandidate.BSSID + " freq=" + roamCandidate.frequency
16771ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                            + " RSSI=" + roamCandidate.level);
1678b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1679b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                networkSwitchType = AUTO_JOIN_ROAMING;
1680e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                mWifiConnectionStatistics.numAutoRoamAttempt++;
1681e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle
1682b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_ROAM,
1683b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                            currentConfiguration.networkId, 1, roamCandidate);
168468fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                found = true;
1685f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1686f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1687b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (VDBG) logDbg("Done attemptAutoJoin status=" + Integer.toString(networkSwitchType));
168868fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle        return found;
1689f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
1690f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle}
1691f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1692