WifiAutoJoinController.java revision b664cfeab6f02e24376ea0a15beb83d142f0b14d
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;
20f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
21f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.NetworkKey;
22f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.NetworkScoreManager;
230c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport android.net.WifiKey;
24c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalleimport android.net.wifi.*;
25f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
26f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.os.SystemClock;
27b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalleimport android.os.Process;
28c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalleimport android.text.TextUtils;
29f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.util.Log;
30f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
310c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport java.util.ArrayList;
32f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.Iterator;
33f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.HashMap;
34f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.List;
35f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
36f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle/**
37f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * AutoJoin controller is responsible for WiFi Connect decision
38f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
39f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * It runs in the thread context of WifiStateMachine
40f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
41f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle */
42f22d23092ab37286a5ef9d257d5bb32c421d2669vandwallepublic class WifiAutoJoinController {
43f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
44f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private Context mContext;
45f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiStateMachine mWifiStateMachine;
46f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiConfigStore mWifiConfigStore;
47f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNative mWifiNative;
48f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
49f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private NetworkScoreManager scoreManager;
50f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNetworkScoreCache mNetworkScoreCache;
51f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
52f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final String TAG = "WifiAutoJoinController ";
53ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean DBG = false;
54ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean VDBG = false;
55f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final boolean mStaStaSupported = false;
56f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final int SCAN_RESULT_CACHE_SIZE = 80;
57f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
58c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    public static int mScanResultMaximumAge = 40000; /* milliseconds unit */
59c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
60453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle    private String mCurrentConfigurationKey = null; //used by autojoin
61f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
62f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private HashMap<String, ScanResult> scanResultCache =
63f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            new HashMap<String, ScanResult>();
64f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
65c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    private WifiConnectionStatistics mWifiConnectionStatistics;
66c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
67c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    /* for debug purpose only : the untrusted SSID we would be connected to if we had VPN */
68c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    String lastUntrustedBSSID = null;
69c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
70c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    /* For debug purpose only: if the scored override a score */
71c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    boolean didOverride = false;
72c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
73931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Lose the non-auth failure blacklisting after 8 hours
744dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListHardMilli = 1000 * 60 * 60 * 8;
75931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Lose some temporary blacklisting after 30 minutes
764dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListSoftMilli = 1000 * 60 * 30;
7727355a942653264388e909a4276196ee63e57811vandwalle
78b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_IDLE = 0;
79b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_ROAMING = 1;
80b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_EXTENDED_ROAMING = 2;
81b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_OUT_OF_NETWORK_ROAMING = 3;
82b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
8397b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle    public static final int HIGH_THRESHOLD_MODIFIER = 5;
8497b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle
85f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    WifiAutoJoinController(Context c, WifiStateMachine w, WifiConfigStore s,
86c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                           WifiConnectionStatistics st, WifiNative n) {
87f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mContext = c;
88f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiStateMachine = w;
89f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore = s;
90f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiNative = n;
91f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mNetworkScoreCache = null;
92c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        mWifiConnectionStatistics = st;
9321bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle        scoreManager =
9421bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                (NetworkScoreManager) mContext.getSystemService(Context.NETWORK_SCORE_SERVICE);
95f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager == null)
96f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("Registered scoreManager NULL " + " service " + Context.NETWORK_SCORE_SERVICE);
97f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
98f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager != null) {
99f13817203179f41620514718c8668ae7e418f8afJeff Davidson            mNetworkScoreCache = new WifiNetworkScoreCache(mContext);
100f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            scoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
101f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        } else {
102f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("No network score service: Couldnt register as a WiFi score Manager, type="
103f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(NetworkKey.TYPE_WIFI)
104f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + " service " + Context.NETWORK_SCORE_SERVICE);
105f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            mNetworkScoreCache = null;
106f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
107f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
108f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
109ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    void enableVerboseLogging(int verbose) {
110ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (verbose > 0 ) {
111abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = true;
112ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = true;
113ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        } else {
114abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = false;
115ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = false;
116ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
117ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    }
118ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle
119931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
120931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * Flush out scan results older than mScanResultMaximumAge
121ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     *
122931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
123f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private void ageScanResultsOut(int delay) {
124f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (delay <= 0) {
125931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            delay = mScanResultMaximumAge; // Something sane
126f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
127b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        long milli = System.currentTimeMillis();
128f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
129f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("ageScanResultsOut delay " + Integer.valueOf(delay) + " size "
130f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.valueOf(scanResultCache.size()) + " now " + Long.valueOf(milli));
131f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
132f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
133f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        Iterator<HashMap.Entry<String,ScanResult>> iter = scanResultCache.entrySet().iterator();
134f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        while (iter.hasNext()) {
135f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            HashMap.Entry<String,ScanResult> entry = iter.next();
136f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult result = entry.getValue();
137f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
138f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((result.seen + delay) < milli) {
139f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                iter.remove();
140f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
141f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
142f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
143f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
144be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle    int addToScanCache(List<ScanResult> scanList) {
145be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        int numScanResultsKnown = 0; // Record number of scan results we knew about
146be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        WifiConfiguration associatedConfig = null;
147f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1480c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        ArrayList<NetworkKey> unknownScanResults = new ArrayList<NetworkKey>();
1490c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
150c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        long nowMs = System.currentTimeMillis();
151f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for(ScanResult result: scanList) {
1521fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng            if (result.SSID == null) continue;
153c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
154c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // Make sure we record the last time we saw this result
155f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            result.seen = System.currentTimeMillis();
156f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
157c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // Fetch the previous instance for this result
158f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult sr = scanResultCache.get(result.BSSID);
159f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (sr != null) {
160931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // If there was a previous cache result for this BSSID, average the RSSI values
161c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                result.averageRssi(sr.level, sr.seen, mScanResultMaximumAge);
162f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
163c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                // Remove the previous Scan Result - this is not necessary
164f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                scanResultCache.remove(result.BSSID);
165e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            }
166e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle
167e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            if (!mNetworkScoreCache.isScoredNetwork(result)) {
168e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                WifiKey wkey;
169e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                // Quoted SSIDs are the only one valid at this stage
170e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                try {
171e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    wkey = new WifiKey("\"" + result.SSID + "\"", result.BSSID);
172e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                } catch (IllegalArgumentException e) {
173e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg("AutoJoinController: received badly encoded SSID=[" + result.SSID +
174e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                            "] ->skipping this network");
175e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    wkey = null;
176e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                }
177e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (wkey != null) {
178e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    NetworkKey nkey = new NetworkKey(wkey);
179e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    //if we don't know this scan result then request a score from the scorer
180e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    unknownScanResults.add(nkey);
181e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                }
182e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (VDBG) {
183e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg(result.SSID + " " + result.BSSID + " rssi="
184e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                            + result.level + " is not scored");
185e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                }
1860c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            } else {
187e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (VDBG) {
188e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    int score = mNetworkScoreCache.getNetworkScore(result);
189e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg(result.SSID + " " + result.BSSID + " rssi="
190e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                            + result.level + " is scored : " + score);
1910c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                }
192f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
193f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
194f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            scanResultCache.put(result.BSSID, new ScanResult(result));
195f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
196be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            // Add this BSSID to the scanResultCache of a Saved WifiConfiguration
197f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            associatedConfig = mWifiConfigStore.updateSavedNetworkHistory(result);
198f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
199be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            // If not successful, try to associate this BSSID to an existing Saved WifiConfiguration
200f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (associatedConfig == null) {
201be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                // We couldn't associate the scan result to a Saved WifiConfiguration
202c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                // Hence it is untrusted
203c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                result.untrusted = true;
204f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                associatedConfig = mWifiConfigStore.associateWithConfiguration(result);
2051fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng                if (associatedConfig != null && associatedConfig.SSID != null) {
206f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (VDBG) {
207f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        logDbg("addToScanCache save associated config "
208f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                + associatedConfig.SSID + " with " + associatedConfig.SSID);
209f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
210be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                    mWifiStateMachine.sendMessage(
211be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                            WifiStateMachine.CMD_AUTO_SAVE_NETWORK, associatedConfig);
212f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
2130d616ef3bf635dff8722e064c0be842676390ed8vandwalle            } else {
2140d616ef3bf635dff8722e064c0be842676390ed8vandwalle                // If the scan result has been blacklisted fir 18 hours -> unblacklist
2150d616ef3bf635dff8722e064c0be842676390ed8vandwalle                long now = System.currentTimeMillis();
2160d616ef3bf635dff8722e064c0be842676390ed8vandwalle                if ((now - result.blackListTimestamp) > loseBlackListHardMilli) {
2170d616ef3bf635dff8722e064c0be842676390ed8vandwalle                    result.setAutoJoinStatus(ScanResult.ENABLED);
2180d616ef3bf635dff8722e064c0be842676390ed8vandwalle                }
219f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
220be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            if (associatedConfig != null) {
221be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                numScanResultsKnown++;
222be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            }
223f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
2240c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
2250c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        if (unknownScanResults.size() != 0) {
2260c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            NetworkKey[] newKeys =
2270c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                    unknownScanResults.toArray(new NetworkKey[unknownScanResults.size()]);
228931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Kick the score manager, we will get updated scores asynchronously
2290c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            scoreManager.requestScores(newKeys);
2300c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        }
231be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        return numScanResultsKnown;
232f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
233f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
234f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void logDbg(String message) {
2350888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle        logDbg(message, false);
236ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    }
237ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
238ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    void logDbg(String message, boolean stackTrace) {
239f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        long now = SystemClock.elapsedRealtimeNanos();
2400888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle        String ts = String.format("[%,d us] ", now / 1000);
241ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (stackTrace) {
242ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            Log.e(TAG, ts + message + " stack:"
243ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[2].getMethodName() + " - "
244ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[3].getMethodName() + " - "
245ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[4].getMethodName() + " - "
246ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[5].getMethodName());
247ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        } else {
248ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            Log.e(TAG, ts + message);
249ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        }
250f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
251f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
252931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Called directly from WifiStateMachine
253be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle    int newSupplicantResults(boolean doAutoJoin) {
254be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        int numScanResultsKnown;
255f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        List<ScanResult> scanList = mWifiStateMachine.syncGetScanResultsList();
256be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        numScanResultsKnown = addToScanCache(scanList);
257f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(mScanResultMaximumAge);
258be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        if (DBG) {
259be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            logDbg("newSupplicantResults size=" + Integer.valueOf(scanResultCache.size())
2609f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                        + " known=" + numScanResultsKnown
2619f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                        + doAutoJoin);
262be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        }
2637806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle        if (doAutoJoin) {
2647806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            attemptAutoJoin();
2657806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle        }
266f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore.writeKnownNetworkHistory();
267be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        return numScanResultsKnown;
268f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
269f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
270f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
271931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
272931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * Not used at the moment
273f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * should be a call back from WifiScanner HAL ??
274f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * this function is not hooked and working yet, it will receive scan results from WifiScanners
275f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * with the list of IEs,then populate the capabilities by parsing the IEs and inject the scan
276f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * results as normal.
277f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     */
278f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void newHalScanResults() {
279f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        List<ScanResult> scanList = null;//mWifiScanner.syncGetScanResultsList();
280f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String akm = WifiParser.parse_akm(null, null);
281f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        logDbg(akm);
282f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        addToScanCache(scanList);
283f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(0);
284f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
285f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore.writeKnownNetworkHistory();
286f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
287f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
288931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
289931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     *  network link quality changed, called directly from WifiTrafficPoller,
290931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * or by listening to Link Quality intent
291931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
292f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void linkQualitySignificantChange() {
293f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
294f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
295f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
296931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
297f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * compare a WifiConfiguration against the current network, return a delta score
298f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * If not associated, and the candidate will always be better
299f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * For instance if the candidate is a home network versus an unknown public wifi,
300f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * the delta will be infinite, else compare Kepler scores etc…
301b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * Negatve return values from this functions are meaningless per se, just trying to
302b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * keep them distinct for debug purpose (i.e. -1, -2 etc...)
303931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
304f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private int compareNetwork(WifiConfiguration candidate) {
305b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (candidate == null)
306b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -3;
307b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
308f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration currentNetwork = mWifiStateMachine.getCurrentWifiConfiguration();
309b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentNetwork == null) {
310c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // Return any absurdly high score, if we are not connected there is no current
311c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // network to...
312b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle           return 1000;
313b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
314f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
315f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (candidate.configKey(true).equals(currentNetwork.configKey(true))) {
316b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -2;
317f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
318f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
319b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle        if (DBG) {
320b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("compareNetwork will compare " + candidate.configKey() + " with current");
321b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle        }
322c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        int order = compareWifiConfigurationsTop(currentNetwork, candidate);
323ede507649471f1113e9e1919812115ca5a6bc0c8vandwalle        return order;
324f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
325f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
326ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    /**
327ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * update the network history fields fo that configuration
328ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if userTriggered, we mark the configuration as "non selfAdded" since the user has seen it
329ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * and took over management
330ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if it is a "connect", remember which network were there at the point of the connect, so
331ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * as those networks get a relative lower score than the selected configuration
33262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle     *
333ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param netId
334ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param userTriggered : if the update come from WiFiManager
335ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param connect : if the update includes a connect
336931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
33762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle    public void updateConfigurationHistory(int netId, boolean userTriggered, boolean connect) {
338f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration selected = mWifiConfigStore.getWifiConfiguration(netId);
339f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (selected == null) {
340c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory nid=" + netId + " no selected configuration!");
341f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return;
342f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
343f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
344e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        if (selected.SSID == null) {
345c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory nid=" + netId +
346c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    " no SSID in selected configuration!");
347e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            return;
348e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        }
349e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
35062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        if (userTriggered) {
351931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Reenable autojoin for this network,
35262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            // since the user want to connect to this configuration
35327355a942653264388e909a4276196ee63e57811vandwalle            selected.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
35462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            selected.selfAdded = false;
35562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        }
356f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
357992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (DBG && userTriggered) {
358f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (selected.connectChoices != null) {
359ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
360f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + Integer.toString(netId) + " now: "
361992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(selected.connectChoices.size())
362992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
363f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
364ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
365992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(netId)
366992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
367f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
368f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
369f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
370ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (connect && userTriggered) {
371ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            boolean found = false;
3722451dbcc4f9641df188326215b204b798eb70c46vandwalle            int choice = 0;
373c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            int size = 0;
3749f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
3759f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // Reset the triggered disabled count, because user wanted to connect to this
3769f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // configuration, and we were not.
3779f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableLowRSSI = 0;
3789f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableBadRSSI = 0;
3799f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableNotHighRSSI = 0;
3809f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredJoinAttempts++;
3819f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
38262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            List<WifiConfiguration> networks =
38362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    mWifiConfigStore.getRecentConfiguredNetworks(12000, false);
384c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (networks != null) size = networks.size();
385c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory found " + size + " networks");
38662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            if (networks != null) {
38762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                for (WifiConfiguration config : networks) {
388992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    if (DBG) {
389992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        logDbg("updateConfigurationHistory got " + config.SSID + " nid="
390992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                                + Integer.toString(config.networkId));
391992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    }
392f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
39362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (selected.configKey(true).equals(config.configKey(true))) {
394ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        found = true;
39562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        continue;
39662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
397f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
3982451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // Compare RSSI values so as to evaluate the strength of the user preference
3992451dbcc4f9641df188326215b204b798eb70c46vandwalle                    int order = compareWifiConfigurationsRSSI(config, selected, null);
4002451dbcc4f9641df188326215b204b798eb70c46vandwalle
4012451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (order < -30) {
4022451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is worse than the visible configuration
4032451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence register a strong choice so as autojoin cannot override this
4042451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // for instance, the user has select a network
4052451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // with 1 bar over a network with 3 bars...
4062451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 60;
4072451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order < -20) {
4082451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 50;
4092451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order < -10) {
4102451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 40;
4112451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order < 10) {
4122451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is about same or has a slightly better RSSI
4132451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence register a weaker choice, here a difference of at least +/-30 in
4142451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // RSSI comparison triggered by autoJoin will override the choice
4152451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 30;
4162451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order <= 30) {
4172451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is better than the visible configuration
4182451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence we do not know if the user prefers this configuration strongly
4192451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 20;
4202451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else {
4212451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 10;
42262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
423f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
424931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // The selected configuration was preferred over a recently seen config
425931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // hence remember the user's choice:
426931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // add the recently seen config to the selected's connectChoices array
427ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
428ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    if (selected.connectChoices == null) {
429ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        selected.connectChoices = new HashMap<String, Integer>();
430ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    }
431ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
432ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    logDbg("updateConfigurationHistory add a choice " + selected.configKey(true)
4330888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                            + " over " + config.configKey(true)
4342451dbcc4f9641df188326215b204b798eb70c46vandwalle                            + " choice " + Integer.toString(choice));
435cf5b8eb8a08c45bd4a82f1f4bb789c8a1b08744fvandwalle
4362451dbcc4f9641df188326215b204b798eb70c46vandwalle                    Integer currentChoice = selected.connectChoices.get(config.configKey(true));
4372451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (currentChoice == null || currentChoice.intValue() < choice) {
4387806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                        if (currentChoice != null) {
4397806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                            // User has made this choice multiple time in a row so bump up
4407806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                            choice += currentChoice.intValue() / 2;
4417806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                        }
4422451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Add the visible config to the selected's connect choice list
4432451dbcc4f9641df188326215b204b798eb70c46vandwalle                        selected.connectChoices.put(config.configKey(true), choice);
4442451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
445f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
44662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (config.connectChoices != null) {
447ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        if (VDBG) {
448ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                            logDbg("updateConfigurationHistory will remove "
44962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                    + selected.configKey(true) + " from " + config.configKey(true));
450ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        }
451931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Remove the selected from the recently seen config's connectChoice list
45262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        config.connectChoices.remove(selected.configKey(true));
4530888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle
4540888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        if (selected.linkedConfigurations != null) {
455931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                           // Remove the selected's linked configuration from the
456931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                           // recently seen config's connectChoice list
4570888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           for (String key : selected.linkedConfigurations.keySet()) {
4580888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                               config.connectChoices.remove(key);
4590888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           }
4600888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        }
46162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
462ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                }
463ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                if (found == false) {
4642451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // We haven't found the configuration that the user just selected in our
4652451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // scan cache.
4662451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // In that case we will need a new scan before attempting to connect to this
4672451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // configuration anyhow and thus we can process the scan results then.
468ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     logDbg("updateConfigurationHistory try to connect to an old network!! : "
469ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                             + selected.configKey());
47062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
471f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
47262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                if (selected.connectChoices != null) {
47362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (VDBG)
474ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        logDbg("updateConfigurationHistory " + Integer.toString(netId)
47562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                + " now: " + Integer.toString(selected.connectChoices.size()));
47662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
477f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
478f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
479992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle
480931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // TODO: write only if something changed
481992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (userTriggered || connect) {
482992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle            mWifiConfigStore.writeKnownNetworkHistory();
483992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        }
484f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
485f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
4862451dbcc4f9641df188326215b204b798eb70c46vandwalle    int getConnectChoice(WifiConfiguration source, WifiConfiguration target) {
4872451dbcc4f9641df188326215b204b798eb70c46vandwalle        Integer choice = null;
4882451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (source == null || target == null) {
4892451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
490f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
491f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
4922451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (source.connectChoices != null
4932451dbcc4f9641df188326215b204b798eb70c46vandwalle                && source.connectChoices.containsKey(target.configKey(true))) {
4942451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = source.connectChoices.get(target.configKey(true));
4952451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else if (source.linkedConfigurations != null) {
496f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            for (String key : source.linkedConfigurations.keySet()) {
497f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(key);
498f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (config != null) {
499f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (config.connectChoices != null) {
5002451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = config.connectChoices.get(target.configKey(true));
501f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
502f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
503f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
5042451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
5052451dbcc4f9641df188326215b204b798eb70c46vandwalle
5062451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (choice == null) {
5072451dbcc4f9641df188326215b204b798eb70c46vandwalle            //We didn't find the connect choice
5082451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
5092451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else {
5102451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice.intValue() < 0) {
5112451dbcc4f9641df188326215b204b798eb70c46vandwalle                choice = 20; // Compatibility with older files
5122451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
5132451dbcc4f9641df188326215b204b798eb70c46vandwalle            return choice.intValue();
5142451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
5152451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
5162451dbcc4f9641df188326215b204b798eb70c46vandwalle
5172451dbcc4f9641df188326215b204b798eb70c46vandwalle
5189f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle    int getScoreFromVisibility(WifiConfiguration.Visibility visibility, int rssiBoost, String dbg) {
5192451dbcc4f9641df188326215b204b798eb70c46vandwalle        int rssiBoost5 = 0;
5202451dbcc4f9641df188326215b204b798eb70c46vandwalle        int score = 0;
5214dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
5222451dbcc4f9641df188326215b204b798eb70c46vandwalle        /**
5232451dbcc4f9641df188326215b204b798eb70c46vandwalle         * Boost RSSI value of 5GHz bands iff the base value is better than threshold
5242451dbcc4f9641df188326215b204b798eb70c46vandwalle         * This implements band preference where we prefer 5GHz if RSSI5 is good enough, whereas
5252451dbcc4f9641df188326215b204b798eb70c46vandwalle         * we prefer 2.4GHz otherwise.
5262451dbcc4f9641df188326215b204b798eb70c46vandwalle         * Note that 2.4GHz doesn't need a boost since at equal power the RSSI is typically
527e67ec726c07410073575473c0f50dc737629f5davandwalle         * at least 6-10 dB higher
5282451dbcc4f9641df188326215b204b798eb70c46vandwalle         */
5299f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle        rssiBoost5 = rssiBoostFrom5GHzRssi(visibility.rssi5, dbg+"->");
5302451dbcc4f9641df188326215b204b798eb70c46vandwalle
5312451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Select which band to use so as to score a
5322451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (visibility.rssi5 + rssiBoost5 > visibility.rssi24) {
5332451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Prefer a's 5GHz
5342451dbcc4f9641df188326215b204b798eb70c46vandwalle            score = visibility.rssi5 + rssiBoost5 + rssiBoost;
5352451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else {
5362451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Prefer a's 2.4GHz
5372451dbcc4f9641df188326215b204b798eb70c46vandwalle            score = visibility.rssi24 + rssiBoost;
538f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
5392451dbcc4f9641df188326215b204b798eb70c46vandwalle
5402451dbcc4f9641df188326215b204b798eb70c46vandwalle        return score;
541f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
542f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
5432451dbcc4f9641df188326215b204b798eb70c46vandwalle    // Compare WifiConfiguration by RSSI, and return a comparison value in the range [-50, +50]
5442451dbcc4f9641df188326215b204b798eb70c46vandwalle    // The result represents "approximately" an RSSI difference measured in dBM
5452451dbcc4f9641df188326215b204b798eb70c46vandwalle    // Adjusted with various parameters:
5462451dbcc4f9641df188326215b204b798eb70c46vandwalle    // +) current network gets a +15 boost
5472451dbcc4f9641df188326215b204b798eb70c46vandwalle    // +) 5GHz signal, if they are strong enough, get a +15 or +25 boost, representing the
5482451dbcc4f9641df188326215b204b798eb70c46vandwalle    // fact that at short range we prefer 5GHz band as it is cleaner of interference and
5492451dbcc4f9641df188326215b204b798eb70c46vandwalle    // provides for wider channels
5502451dbcc4f9641df188326215b204b798eb70c46vandwalle    int compareWifiConfigurationsRSSI(WifiConfiguration a, WifiConfiguration b,
5512451dbcc4f9641df188326215b204b798eb70c46vandwalle                                      String currentConfiguration) {
552f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
5532451dbcc4f9641df188326215b204b798eb70c46vandwalle
5542451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Boost used so as to favor current config
5552451dbcc4f9641df188326215b204b798eb70c46vandwalle        int aRssiBoost = 0;
5562451dbcc4f9641df188326215b204b798eb70c46vandwalle        int bRssiBoost = 0;
5572451dbcc4f9641df188326215b204b798eb70c46vandwalle
5582451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreA;
5592451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreB;
5602451dbcc4f9641df188326215b204b798eb70c46vandwalle
5612451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Retrieve the visibility
562f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility astatus = a.visibility;
563f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility bstatus = b.visibility;
564f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (astatus == null || bstatus == null) {
5652451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Error visibility wasn't set
566b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurations NULL band status!");
567f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 0;
568f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
5692451dbcc4f9641df188326215b204b798eb70c46vandwalle
5702451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply Hysteresis, boost RSSI of current configuration
5712451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (null != currentConfiguration) {
5722451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (a.configKey().equals(currentConfiguration)) {
573b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                aRssiBoost = +10;
5742451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (b.configKey().equals(currentConfiguration)) {
575b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                bRssiBoost = +10;
5762451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
577b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle
578b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle
5792451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
5802451dbcc4f9641df188326215b204b798eb70c46vandwalle
5812451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG)  {
582b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsRSSI: " + a.configKey()
583c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + " " + Integer.toString(astatus.rssi24)
584c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + "," + Integer.toString(astatus.rssi5)
5852451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " boost=" + Integer.toString(aRssiBoost)
586c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + " " + b.configKey() + " "
587c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + Integer.toString(bstatus.rssi24) + ","
588c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + Integer.toString(bstatus.rssi5)
5892451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " boost=" + Integer.toString(bRssiBoost)
5902451dbcc4f9641df188326215b204b798eb70c46vandwalle            );
591f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
5922451dbcc4f9641df188326215b204b798eb70c46vandwalle
5939f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle        scoreA = getScoreFromVisibility(astatus, aRssiBoost, a.configKey());
5949f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle        scoreB = getScoreFromVisibility(bstatus, bRssiBoost, b.configKey());
5952451dbcc4f9641df188326215b204b798eb70c46vandwalle
5962451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Compare a and b
5972451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If a score is higher then a > b and the order is descending (negative)
5982451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If b score is higher then a < b and the order is ascending (positive)
5992451dbcc4f9641df188326215b204b798eb70c46vandwalle        order = scoreB - scoreA;
6002451dbcc4f9641df188326215b204b798eb70c46vandwalle
6012451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Normalize the order to [-50, +50]
6022451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (order > 50) order = 50;
6032451dbcc4f9641df188326215b204b798eb70c46vandwalle        else if (order < -50) order = -50;
6042451dbcc4f9641df188326215b204b798eb70c46vandwalle
6052451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
6062451dbcc4f9641df188326215b204b798eb70c46vandwalle            String prefer = " = ";
6072451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (order > 0) {
6082451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " < "; // Ascending
6092451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (order < 0) {
6102451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " > "; // Descending
6112451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
612b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsRSSI " + a.configKey()
6132451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + a.visibility.rssi24
6142451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.rssi5
6152451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + a.visibility.num24
6162451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.num5 + ")"
617e67ec726c07410073575473c0f50dc737629f5davandwalle                    + " scorea=" + scoreA
6182451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + prefer + b.configKey()
6192451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + b.visibility.rssi24
6202451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.rssi5
6212451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + b.visibility.num24
6222451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.num5 + ")"
623e67ec726c07410073575473c0f50dc737629f5davandwalle                    + " scoreb=" + scoreB
6242451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " -> " + order);
6252451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
6262451dbcc4f9641df188326215b204b798eb70c46vandwalle
627f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
628f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
629f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
6304dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
6312451dbcc4f9641df188326215b204b798eb70c46vandwalle    int compareWifiConfigurationsWithScorer(WifiConfiguration a, WifiConfiguration b) {
6322451dbcc4f9641df188326215b204b798eb70c46vandwalle
6332451dbcc4f9641df188326215b204b798eb70c46vandwalle        int aRssiBoost = 0;
6342451dbcc4f9641df188326215b204b798eb70c46vandwalle        int bRssiBoost = 0;
6352451dbcc4f9641df188326215b204b798eb70c46vandwalle
6362451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply Hysteresis : boost RSSI of current configuration before
6372451dbcc4f9641df188326215b204b798eb70c46vandwalle        // looking up the score
6382451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (null != mCurrentConfigurationKey) {
6392451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (a.configKey().equals(mCurrentConfigurationKey)) {
640c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                aRssiBoost += 20;
6412451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (b.configKey().equals(mCurrentConfigurationKey)) {
642c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                bRssiBoost += 20;
6432451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
6442451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
6452451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreA = getConfigNetworkScore(a, 3000, aRssiBoost);
646ede507649471f1113e9e1919812115ca5a6bc0c8vandwalle        int scoreB = getConfigNetworkScore(b, 3000, bRssiBoost);
6472451dbcc4f9641df188326215b204b798eb70c46vandwalle
6482451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Both configurations need to have a score for the scorer to be used
6492451dbcc4f9641df188326215b204b798eb70c46vandwalle        // ...and the scores need to be different:-)
6502451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (scoreA == WifiNetworkScoreCache.INVALID_NETWORK_SCORE
6512451dbcc4f9641df188326215b204b798eb70c46vandwalle                || scoreB == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
652e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            if (VDBG)  {
653b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurationsWithScorer no-scores: "
654e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                        + a.configKey()
655e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                        + " "
656e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                        + b.configKey());
657e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            }
6582451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
6592451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
6602451dbcc4f9641df188326215b204b798eb70c46vandwalle
6612451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
6622451dbcc4f9641df188326215b204b798eb70c46vandwalle            String prefer = " = ";
6632451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (scoreA < scoreB) {
6642451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " < ";
6652451dbcc4f9641df188326215b204b798eb70c46vandwalle            } if (scoreA > scoreB) {
6662451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " > ";
6672451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
668b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsWithScorer " + a.configKey()
6692451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + a.visibility.rssi24
6702451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.rssi5
6712451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + a.visibility.num24
6722451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.num5 + ")"
673e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    + " sc=" + scoreA
6742451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + prefer + b.configKey()
6752451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + b.visibility.rssi24
6762451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.rssi5
6772451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + b.visibility.num24
6782451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.num5 + ")"
679e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    + " sc=" + scoreB
6802451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " -> " + Integer.toString(scoreB - scoreA));
6812451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
682c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
6832451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If scoreA > scoreB, the comparison is descending hence the return value is negative
6842451dbcc4f9641df188326215b204b798eb70c46vandwalle        return scoreB - scoreA;
6852451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
6862451dbcc4f9641df188326215b204b798eb70c46vandwalle
687f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    int compareWifiConfigurations(WifiConfiguration a, WifiConfiguration b) {
688f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
689117be607246604e875de62aa8cdd99700b77a2b4vandwalle        String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
690f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        boolean linked = false;
691f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
692453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if ((a.linkedConfigurations != null) && (b.linkedConfigurations != null)
693453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (a.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)
694453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (b.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)) {
6952451dbcc4f9641df188326215b204b798eb70c46vandwalle            if ((a.linkedConfigurations.get(b.configKey(true)) != null)
6962451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && (b.linkedConfigurations.get(a.configKey(true)) != null)) {
697f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                linked = true;
698f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
699f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
700f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
701f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (a.ephemeral && b.ephemeral == false) {
702f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
703b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurations ephemeral and prefers " + b.configKey()
704453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + a.configKey());
705f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
706931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            return 1; // b is of higher priority - ascending
707f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
708f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (b.ephemeral && a.ephemeral == false) {
709f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
710b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurations ephemeral and prefers " + a.configKey()
711453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey());
712f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
713931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            return -1; // a is of higher priority - descending
714f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
715f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
7162451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply RSSI, in the range [-5, +5]
7172451dbcc4f9641df188326215b204b798eb70c46vandwalle        // after band adjustment, +n difference roughly corresponds to +10xn dBm
7182451dbcc4f9641df188326215b204b798eb70c46vandwalle        order = order + compareWifiConfigurationsRSSI(a, b, mCurrentConfigurationKey);
719f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
7202451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If the configurations are not linked, compare by user's choice, only a
7212451dbcc4f9641df188326215b204b798eb70c46vandwalle        // very high RSSI difference can then override the choice
7222451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (!linked) {
7232451dbcc4f9641df188326215b204b798eb70c46vandwalle            int choice;
724f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
7252451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = getConnectChoice(a, b);
7262451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice > 0) {
727931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of higher priority - descending
7282451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = order - choice;
729f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG) {
730b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers " + a.configKey()
731453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + " over " + b.configKey()
732b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " due to user choice of " + choice
733b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " order -> " + Integer.toString(order));
734f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
7352451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
7362451dbcc4f9641df188326215b204b798eb70c46vandwalle
7372451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = getConnectChoice(b, a);
7382451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice > 0) {
739931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of lower priority - ascending
7402451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = order + choice;
7414dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                if (VDBG) {
742b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers " + b.configKey() + " over "
743b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + a.configKey() + " due to user choice of " + choice
744b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " order ->" + Integer.toString(order));
745f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
746f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
747f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
748ede1310be531a84faa08f02c3fd243448dd936ddvandwalle
749f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order == 0) {
750931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // We don't know anything - pick the last seen i.e. K behavior
751931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // we should do this only for recently picked configurations
752f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (a.priority > b.priority) {
753931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of higher priority - descending
7542451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (VDBG) {
755b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers -1 " + a.configKey() + " over "
756453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + b.configKey() + " due to priority");
757f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
758f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
759f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                order = -1;
760f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else if (a.priority < b.priority) {
761931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of lower priority - ascending
7622451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (VDBG) {
763b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers +1 " + b.configKey() + " over "
764453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + a.configKey() + " due to priority");
765f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
7662451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = 1;
767f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
768f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
769f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
770f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String sorder = " == ";
771931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        if (order > 0) {
772f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " < ";
773931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        } else if (order < 0) {
774f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " > ";
775931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        }
776f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
7772451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
778b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("compareWifiConfigurations: " + a.configKey() + sorder
779453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    + b.configKey() + " order " + Integer.toString(order));
780f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
781f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
782f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
783f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
784f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
785c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    boolean isBadCandidate(int rssi5, int rssi24) {
786c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        return (rssi5 < -80 && rssi24 < -90);
787c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    }
788c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
789c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    int compareWifiConfigurationsTop(WifiConfiguration a, WifiConfiguration b) {
790c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        int scorerOrder = compareWifiConfigurationsWithScorer(a, b);
791c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        int order = compareWifiConfigurations(a, b);
792c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
793c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        if (scorerOrder * order < 0) {
794b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (VDBG) {
795b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    -> compareWifiConfigurationsTop: " +
796b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                        "scorer override " + scorerOrder + " " + order);
797b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
798c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // For debugging purpose, remember that an override happened
799c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // during that autojoin Attempt
800c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            didOverride = true;
801c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            a.numScorerOverride++;
802c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            b.numScorerOverride++;
803c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        }
804c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
805c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        if (scorerOrder != 0) {
806c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // If the scorer came up with a result then use the scorer's result, else use
807c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // the order provided by the base comparison function
808c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            order = scorerOrder;
809c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        }
810c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        return order;
811c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    }
812c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
8139f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle    public int rssiBoostFrom5GHzRssi(int rssi, String dbg) {
814e67ec726c07410073575473c0f50dc737629f5davandwalle        if (rssi
815e67ec726c07410073575473c0f50dc737629f5davandwalle                > mWifiConfigStore.thresholdBandPreferenceLowRssi5) {
816e67ec726c07410073575473c0f50dc737629f5davandwalle            // Boost by 2 dB for each point
817e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Start boosting at -65
818e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Boost by 20 if above -55
819e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Boost by 40 if abore -45
8209f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            int boost = mWifiConfigStore.factorBandPreferenceLowRssi5
8219f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    *(rssi - mWifiConfigStore.thresholdBandPreferenceLowRssi5);
822e67ec726c07410073575473c0f50dc737629f5davandwalle            if (boost > 50) {
823e67ec726c07410073575473c0f50dc737629f5davandwalle                // 50 dB boost is set so as to overcome the hysteresis of +20 plus a difference of
824e67ec726c07410073575473c0f50dc737629f5davandwalle                // 25 dB between 2.4 and 5GHz band. This allows jumping from 2.4 to 5GHz
825e67ec726c07410073575473c0f50dc737629f5davandwalle                // consistently
826e67ec726c07410073575473c0f50dc737629f5davandwalle                boost = 50;
827e67ec726c07410073575473c0f50dc737629f5davandwalle            }
8289f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            if (VDBG && dbg != null) {
829b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("        " + dbg + ":    rssi5 " + rssi + " boost " + boost);
8309f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            }
831e67ec726c07410073575473c0f50dc737629f5davandwalle            return boost;
832e67ec726c07410073575473c0f50dc737629f5davandwalle        }
833e67ec726c07410073575473c0f50dc737629f5davandwalle
834e67ec726c07410073575473c0f50dc737629f5davandwalle        if (rssi
835e67ec726c07410073575473c0f50dc737629f5davandwalle                < mWifiConfigStore.thresholdBandPreferenceRssi24) {
836e67ec726c07410073575473c0f50dc737629f5davandwalle            // penalize by 10 if < -75
837e67ec726c07410073575473c0f50dc737629f5davandwalle            return -10;
838e67ec726c07410073575473c0f50dc737629f5davandwalle        }
839e67ec726c07410073575473c0f50dc737629f5davandwalle        return 0;
840e67ec726c07410073575473c0f50dc737629f5davandwalle    }
841c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        /**
842e67ec726c07410073575473c0f50dc737629f5davandwalle         * attemptRoam() function implements the core of the same SSID switching algorithm
843e67ec726c07410073575473c0f50dc737629f5davandwalle         *
844e67ec726c07410073575473c0f50dc737629f5davandwalle         * Run thru all recent scan result of a WifiConfiguration and select the
845e67ec726c07410073575473c0f50dc737629f5davandwalle         * best one.
846c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle         */
847e67ec726c07410073575473c0f50dc737629f5davandwalle    public ScanResult attemptRoam(ScanResult a,
848e67ec726c07410073575473c0f50dc737629f5davandwalle                                  WifiConfiguration current, int age, String currentBSSID) {
849b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current == null) {
850b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
851b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam not associated");
852b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
853e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
8544dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
855b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current.scanResultCache == null) {
856b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
857b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam no scan cache");
858b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
859e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
8604dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
861b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle        if (current.scanResultCache.size() > 6) {
862b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
863c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptRoam scan cache size "
864c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + current.scanResultCache.size() + " --> bail");
865b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
866931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Implement same SSID roaming only for configurations
867c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            // that have less than 4 BSSIDs
868e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
8694dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
870b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
871b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current.bssidOwnerUid!= 0 && current.bssidOwnerUid != Process.WIFI_UID) {
872b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (DBG)   {
873c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptRoam BSSID owner is "
874c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + Long.toString(current.bssidOwnerUid) + " -> bail");
875b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
876e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
8774dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
8784dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
879931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Determine which BSSID we want to associate to, taking account
880c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle        // relative strength of 5 and 2.4 GHz BSSIDs
8812451dbcc4f9641df188326215b204b798eb70c46vandwalle        long nowMs = System.currentTimeMillis();
8824dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
88397b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle        for (ScanResult b : current.scanResultCache.values()) {
88497b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int bRssiBoost5 = 0;
88597b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int aRssiBoost5 = 0;
88697b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int bRssiBoost = 0;
88797b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int aRssiBoost = 0;
888931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            if ((b.seen == 0) || (b.BSSID == null)
8890d616ef3bf635dff8722e064c0be842676390ed8vandwalle                    || ((nowMs - b.seen) > age)
8900d616ef3bf635dff8722e064c0be842676390ed8vandwalle                    || b.autoJoinStatus != ScanResult.ENABLED) {
8914dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
8923a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
8934dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
894931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Pick first one
8954dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (a == null) {
8964dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                a = b;
8974dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
8984dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
8994dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
9002451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Apply hysteresis: we favor the currentBSSID by giving it a boost
9017806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentBSSID != null && currentBSSID.equals(b.BSSID)) {
902931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Reduce the benefit of hysteresis if RSSI <= -75
9038c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                if (b.level <= mWifiConfigStore.thresholdBandPreferenceRssi24) {
90497b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                    bRssiBoost = +8;
905c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
90697b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                    bRssiBoost = +14;
907c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
9084dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
9097806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentBSSID != null && currentBSSID.equals(a.BSSID)) {
9108c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                if (a.level <= mWifiConfigStore.thresholdBandPreferenceRssi24) {
911931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Reduce the benefit of hysteresis if RSSI <= -75
91297b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                    aRssiBoost = +8;
913c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
91497b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                    aRssiBoost = +14;
915c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
9164dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
9172451dbcc4f9641df188326215b204b798eb70c46vandwalle
91897b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            // Favor 5GHz: give a boost to 5GHz BSSIDs, with a slightly progressive curve
9192451dbcc4f9641df188326215b204b798eb70c46vandwalle            //   Boost the BSSID if it is on 5GHz, above a threshold
9202451dbcc4f9641df188326215b204b798eb70c46vandwalle            //   But penalize it if it is on 5GHz and below threshold
92197b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //
92297b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   With he current threshold values, 5GHz network with RSSI above -55
92397b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   Are given a boost of 30DB which is enough to overcome the current BSSID
92497b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   hysteresis (+14) plus 2.4/5 GHz signal strength difference on most cases
9259f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            //
9269f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // The "current BSSID" Boost must be added to the BSSID's level so as to introduce\
9279f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // soem amount of hysteresis
928e67ec726c07410073575473c0f50dc737629f5davandwalle            if (b.is5GHz()) {
9299f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                bRssiBoost5 = rssiBoostFrom5GHzRssi(b.level + bRssiBoost, b.BSSID);
9304dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
931e67ec726c07410073575473c0f50dc737629f5davandwalle            if (a.is5GHz()) {
9329f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                aRssiBoost5 = rssiBoostFrom5GHzRssi(a.level + aRssiBoost, a.BSSID);
9334dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
9344dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
9354dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (VDBG)  {
936c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                String comp = " < ";
937c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
938c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    comp = " > ";
939c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
9404dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                logDbg("attemptRoam: "
941c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + b.BSSID + " rssi=" + b.level + " boost=" + Integer.toString(bRssiBoost)
94297b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                        + "/" + Integer.toString(bRssiBoost5) + " freq=" + b.frequency
94397b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                        + comp
944c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + a.BSSID + " rssi=" + a.level + " boost=" + Integer.toString(aRssiBoost)
945c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + "/" + Integer.toString(aRssiBoost5) + " freq=" + a.frequency);
946c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            }
947c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle
9482451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Compare the RSSIs after applying the hysteresis boost and the 5GHz
9492451dbcc4f9641df188326215b204b798eb70c46vandwalle            // boost if applicable
950c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
951931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // b is the better BSSID
952c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                a = b;
9534dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
9544dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
9553a2a3d226881cce8a4e511302231d843b0def303vandwalle        if (a != null) {
9563a2a3d226881cce8a4e511302231d843b0def303vandwalle            if (VDBG)  {
9577806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                StringBuilder sb = new StringBuilder();
958e67ec726c07410073575473c0f50dc737629f5davandwalle                sb.append("attemptRoam: " + current.configKey() +
959e67ec726c07410073575473c0f50dc737629f5davandwalle                        " Found " + a.BSSID + " rssi=" + a.level + " freq=" + a.frequency);
9607806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                if (currentBSSID != null) {
9617806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                    sb.append(" Current: " + currentBSSID);
9627806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                }
9637806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                sb.append("\n");
9647806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                logDbg(sb.toString());
9653a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
9664dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
9673a2a3d226881cce8a4e511302231d843b0def303vandwalle        return a;
9684dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    }
9694dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
970931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
9712451dbcc4f9641df188326215b204b798eb70c46vandwalle     * getNetworkScore()
9722451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
9732451dbcc4f9641df188326215b204b798eb70c46vandwalle     * if scorer is present, get the network score of a WifiConfiguration
9742451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
9752451dbcc4f9641df188326215b204b798eb70c46vandwalle     * Note: this should be merge with setVisibility
9762451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
9772451dbcc4f9641df188326215b204b798eb70c46vandwalle     * @param config
9782451dbcc4f9641df188326215b204b798eb70c46vandwalle     * @return score
9792451dbcc4f9641df188326215b204b798eb70c46vandwalle     */
9802451dbcc4f9641df188326215b204b798eb70c46vandwalle    int getConfigNetworkScore(WifiConfiguration config, int age, int rssiBoost) {
9812451dbcc4f9641df188326215b204b798eb70c46vandwalle
9822451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (mNetworkScoreCache == null) {
983e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (VDBG) {
984b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("       getConfigNetworkScore for " + config.configKey()
985e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + "  -> no scorer, hence no scores");
986e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
9871db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            return WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
9881db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        }
9891db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        if (config.scanResultCache == null) {
990e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (VDBG) {
991b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("       getConfigNetworkScore for " + config.configKey()
992e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " -> no scan cache");
993e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
9941db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            return WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
9952451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
9962451dbcc4f9641df188326215b204b798eb70c46vandwalle
9972451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Get current date
9982451dbcc4f9641df188326215b204b798eb70c46vandwalle        long nowMs = System.currentTimeMillis();
9992451dbcc4f9641df188326215b204b798eb70c46vandwalle
10001db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        int startScore = -10000;
10011db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle
10022451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Run thru all cached scan results
10031db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        for (ScanResult result : config.scanResultCache.values()) {
10042451dbcc4f9641df188326215b204b798eb70c46vandwalle            if ((nowMs - result.seen) < age) {
10052451dbcc4f9641df188326215b204b798eb70c46vandwalle                int sc = mNetworkScoreCache.getNetworkScore(result, rssiBoost);
10061db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle                if (sc > startScore) {
10071db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle                    startScore = sc;
10082451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
10092451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
10102451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
10111db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        if (startScore == -10000) {
10121db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            startScore = WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
10131db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        }
1014e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle        if (VDBG) {
1015e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (startScore == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
1016b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    getConfigNetworkScore for " + config.configKey()
1017e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " -> no available score");
1018e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            } else {
1019b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    getConfigNetworkScore for " + config.configKey()
1020e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " boost=" + Integer.toString(rssiBoost)
1021e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " score = " + Integer.toString(startScore));
1022e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
1023e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle        }
1024e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle
10251db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        return startScore;
10262451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
10272451dbcc4f9641df188326215b204b798eb70c46vandwalle
10282451dbcc4f9641df188326215b204b798eb70c46vandwalle    /**
1029931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * attemptAutoJoin() function implements the core of the a network switching algorithm
1030931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
1031f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void attemptAutoJoin() {
1032c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        didOverride = false;
1033b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        int networkSwitchType = AUTO_JOIN_IDLE;
10344dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
10358c9088d11880553458f09377cc60d6eb7e66747bvandwalle        String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
10368c9088d11880553458f09377cc60d6eb7e66747bvandwalle
1037931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Reset the currentConfiguration Key, and set it only if WifiStateMachine and
1038453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        // supplicant agree
1039453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        mCurrentConfigurationKey = null;
1040453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        WifiConfiguration currentConfiguration = mWifiStateMachine.getCurrentWifiConfiguration();
1041453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
1042f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration candidate = null;
1043f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1044931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Obtain the subset of recently seen networks
104527355a942653264388e909a4276196ee63e57811vandwalle        List<WifiConfiguration> list = mWifiConfigStore.getRecentConfiguredNetworks(3000, false);
1046f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (list == null) {
1047f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG)  logDbg("attemptAutoJoin nothing");
1048f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return;
1049f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1050f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1051931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Find the currently connected network: ask the supplicant directly
1052f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String val = mWifiNative.status();
1053f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String status[] = val.split("\\r?\\n");
1054f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
1055f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("attemptAutoJoin() status=" + val + " split="
1056f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(status.length));
1057f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1058f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1059b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        int supplicantNetId = -1;
1060f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (String key : status) {
1061f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (key.regionMatches(0, "id=", 0, 3)) {
1062f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int idx = 3;
1063b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                supplicantNetId = 0;
1064f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                while (idx < key.length()) {
1065f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    char c = key.charAt(idx);
1066f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1067f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if ((c >= 0x30) && (c <= 0x39)) {
1068b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        supplicantNetId *= 10;
1069b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        supplicantNetId += c - 0x30;
1070f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        idx++;
1071f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    } else {
1072f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        break;
1073f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
1074f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
107556d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle            } else if (key.contains("wpa_state=ASSOCIATING")
107656d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                    || key.contains("wpa_state=ASSOCIATED")
107756d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                    || key.contains("wpa_state=FOUR_WAY_HANDSHAKE")
107856d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                    || key.contains("wpa_state=GROUP_KEY_HANDSHAKE")) {
107956d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                if (DBG) {
108056d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                    logDbg("attemptAutoJoin: bail out due to sup state " + key);
108156d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                }
108256d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // After WifiStateMachine ask the supplicant to associate or reconnect
108356d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // we might still obtain scan results from supplicant
108456d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // however the supplicant state in the mWifiInfo and supplicant state tracker
108556d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // are updated when we get the supplicant state change message which can be
108656d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // processed after the SCAN_RESULT message, so at this point the framework doesn't
108756d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // know that supplicant is ASSOCIATING.
108856d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // A good fix for this race condition would be for the WifiStateMachine to add
108956d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // a new transient state where it expects to get the supplicant message indicating
109056d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // that it started the association process and within which critical operations
109156d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // like autojoin should be deleted.
109256d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle
109356d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // This transient state would remove the need for the roam Wathchdog which
109456d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // basically does that.
109556d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle
109656d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // At the moment, we just query the supplicant state synchronously with the
109756d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // mWifiNative.status() command, which allow us to know that
109856d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // supplicant has started association process, even though we didnt yet get the
109956d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // SUPPLICANT_STATE_CHANGE message.
110056d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                return;
1101f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1102f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1103ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (DBG) {
11047806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            String conf = "";
1105b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String last = "";
11067806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentConfiguration != null) {
1107b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                conf = " curent=" + currentConfiguration.configKey();
1108b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1109b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (lastSelectedConfiguration != null) {
1110b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                last = " last=" + last;
11117806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            }
1112ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            logDbg("attemptAutoJoin() num recent config " + Integer.toString(list.size())
1113b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + conf + last
1114b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + " ---> suppNetId=" + Integer.toString(supplicantNetId));
1115ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
1116f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1117453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if (currentConfiguration != null) {
11182451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (supplicantNetId != currentConfiguration.networkId
11192451dbcc4f9641df188326215b204b798eb70c46vandwalle                    //https://b.corp.google.com/issue?id=16484607
11202451dbcc4f9641df188326215b204b798eb70c46vandwalle                    //mark this confition as an error only if the mismatched networkId are valid
11212451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID
11222451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && currentConfiguration.networkId != WifiConfiguration.INVALID_NETWORK_ID) {
1123453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("attemptAutoJoin() ERROR wpa_supplicant out of sync nid="
1124b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        + Integer.toString(supplicantNetId) + " WifiStateMachine="
1125453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + Integer.toString(currentConfiguration.networkId));
1126b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                mWifiStateMachine.disconnectCommand();
1127b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                return;
1128453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            } else {
1129453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                mCurrentConfigurationKey = currentConfiguration.configKey();
1130453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            }
11318c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle        } else {
11328c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle            if (supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID) {
11338c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                // Maybe in the process of associating, skip this attempt
11348c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                return;
11358c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle            }
1136453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        }
1137453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
1138b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        int currentNetId = -1;
1139b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentConfiguration != null) {
1140931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // If we are associated to a configuration, it will
1141b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            // be compared thru the compareNetwork function
1142b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            currentNetId = currentConfiguration.networkId;
1143b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
1144b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle
1145931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1146931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * Run thru all visible configurations without looking at the one we
1147c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle         * are currently associated to
11484dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle         * select Best Network candidate from known WifiConfigurations
1149931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1150f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (WifiConfiguration config : list) {
1151f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((config.status == WifiConfiguration.Status.DISABLED)
1152f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    && (config.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE)) {
1153ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
1154b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("attemptAutoJoin skip candidate due to auth failure: "
1155ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + config.configKey(true));
1156ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
1157f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1158f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1159453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
1160e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            if (config.SSID == null) {
1161b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                continue;
1162e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            }
1163e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
116427355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
116527355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
1166931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Avoid networks disabled because of AUTH failure altogether
1167ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
1168ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                    logDbg("attemptAutoJoin skip candidate due to auto join status "
1169ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + Integer.toString(config.autoJoinStatus) + " key "
1170ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + config.configKey(true));
1171ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
1172f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1173f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1174f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1175931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to un-blacklist based on elapsed time
117627355a942653264388e909a4276196ee63e57811vandwalle            if (config.blackListTimestamp > 0) {
117727355a942653264388e909a4276196ee63e57811vandwalle                long now = System.currentTimeMillis();
117827355a942653264388e909a4276196ee63e57811vandwalle                if (now < config.blackListTimestamp) {
1179931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    /**
1180931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * looks like there was a change in the system clock since we black listed, and
1181931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * timestamp is not meaningful anymore, hence lose it.
1182931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * this event should be rare enough so that we still want to lose the black list
11832451dbcc4f9641df188326215b204b798eb70c46vandwalle                     */
118427355a942653264388e909a4276196ee63e57811vandwalle                    config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
118527355a942653264388e909a4276196ee63e57811vandwalle                } else {
11864dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    if ((now - config.blackListTimestamp) > loseBlackListHardMilli) {
1187931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Reenable it after 18 hours, i.e. next day
118827355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
11894dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    } else if ((now - config.blackListTimestamp) > loseBlackListSoftMilli) {
1190931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Lose blacklisting due to bad link
119127355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(config.autoJoinStatus - 8);
119227355a942653264388e909a4276196ee63e57811vandwalle                    }
119327355a942653264388e909a4276196ee63e57811vandwalle                }
119427355a942653264388e909a4276196ee63e57811vandwalle            }
119527355a942653264388e909a4276196ee63e57811vandwalle
1196931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to unblacklist based on good visibility
11978c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle            if (config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Soft
11988c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    && config.visibility.rssi24
11998c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    < mWifiConfigStore.thresholdUnblacklistThreshold24Soft) {
120027355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
1201c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    logDbg("attemptAutoJoin do not unblacklist due to low visibility "
12024dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.autoJoinStatus
12034dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " key " + config.configKey(true)
12044dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " rssi=(" + config.visibility.rssi24
12054dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.rssi5
12064dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
12074dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
120827355a942653264388e909a4276196ee63e57811vandwalle                }
12098c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle            } else if (config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Hard
12108c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    && config.visibility.rssi24
12118c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    < mWifiConfigStore.thresholdUnblacklistThreshold24Hard) {
1212931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // If the network is simply temporary disabled, don't allow reconnect until
1213931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // RSSI becomes good enough
121427355a942653264388e909a4276196ee63e57811vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 1);
121527355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
121627355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped soft -> status="
121727355a942653264388e909a4276196ee63e57811vandwalle                            + config.autoJoinStatus
1218b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " " + config.configKey(true) + " rssi=("
12194dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
12204dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
12214dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
122227355a942653264388e909a4276196ee63e57811vandwalle                }
122327355a942653264388e909a4276196ee63e57811vandwalle            } else {
1224c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 3);
122527355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
122627355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped hard -> status="
122727355a942653264388e909a4276196ee63e57811vandwalle                            + config.autoJoinStatus
1228b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " " + config.configKey(true) + " rssi=("
12294dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
12304dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
12314dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
123227355a942653264388e909a4276196ee63e57811vandwalle                }
123327355a942653264388e909a4276196ee63e57811vandwalle            }
123427355a942653264388e909a4276196ee63e57811vandwalle
123527355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
123627355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED) {
1237931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Network is blacklisted, skip
12384dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                if (DBG) {
12394dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    logDbg("attemptAutoJoin skip blacklisted -> status="
12404dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.autoJoinStatus
1241b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " " + config.configKey(true) + " rssi=("
12424dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
12434dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
12444dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
12454dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                }
124627355a942653264388e909a4276196ee63e57811vandwalle                continue;
124727355a942653264388e909a4276196ee63e57811vandwalle            }
1248f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (config.networkId == currentNetId) {
1249ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
125021bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    logDbg("attemptAutoJoin skip current candidate  "
125121bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                            + Integer.toString(currentNetId)
1252ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + " key " + config.configKey(true));
1253ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
1254f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1255f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1256f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
125721bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle            if (lastSelectedConfiguration == null ||
125821bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    !config.configKey().equals(lastSelectedConfiguration)) {
1259c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // Don't try to autojoin a network that is too far but
1260c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // If that configuration is a user's choice however, try anyway
12618c9088d11880553458f09377cc60d6eb7e66747bvandwalle                if (config.visibility == null) {
12628c9088d11880553458f09377cc60d6eb7e66747bvandwalle                    continue;
12638c9088d11880553458f09377cc60d6eb7e66747bvandwalle                }
12648c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                if (config.visibility.rssi5
12658c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                        < mWifiConfigStore.thresholdInitialAutoJoinAttemptMin5RSSI
1266c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        && config.visibility.rssi24
12678c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                        < mWifiConfigStore.thresholdInitialAutoJoinAttemptMin24RSSI) {
12684dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    if (DBG) {
1269ede507649471f1113e9e1919812115ca5a6bc0c8vandwalle                        logDbg("attemptAutoJoin skip due to low visibility -> status="
12704dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + config.autoJoinStatus
12714dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + " key " + config.configKey(true) + " rssi="
12724dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + config.visibility.rssi24 + ", " + config.visibility.rssi5
12734dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + " num=" + config.visibility.num24
12744dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + ", " + config.visibility.num5);
12754dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    }
12768c9088d11880553458f09377cc60d6eb7e66747bvandwalle                    continue;
12778c9088d11880553458f09377cc60d6eb7e66747bvandwalle                }
12789f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                if (config.noInternetAccess) {
12799f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    // Avoid autojoining this network because last time we used it, it didn't
12809f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    // have internet access
12819f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    if (DBG) {
12829f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                        logDbg("attemptAutoJoin skip candidate due to noInternetAccess flag "
12839f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                                + config.configKey(true));
12849f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    }
12859f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    continue;
12869f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                }
12878c9088d11880553458f09377cc60d6eb7e66747bvandwalle            }
12888c9088d11880553458f09377cc60d6eb7e66747bvandwalle
1289ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            if (DBG) {
1290c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptAutoJoin trying candidate id="
1291c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + Integer.toString(config.networkId) + " "
1292b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                        + config.configKey(true)
12934dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                        + " status=" + config.autoJoinStatus);
1294ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            }
1295f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1296f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate == null) {
1297f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                candidate = config;
1298f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
1299f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)  {
1300453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("attemptAutoJoin will compare candidate  " + candidate.configKey()
13014dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " with " + config.configKey());
1302f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1303c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                int order = compareWifiConfigurationsTop(candidate, config);
13042451dbcc4f9641df188326215b204b798eb70c46vandwalle
13052451dbcc4f9641df188326215b204b798eb70c46vandwalle                // The lastSelectedConfiguration is the configuration the user has manually selected
1306c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // thru WifiPicker, or that a 3rd party app asked us to connect to via the
13072451dbcc4f9641df188326215b204b798eb70c46vandwalle                // enableNetwork with disableOthers=true WifiManager API
13082451dbcc4f9641df188326215b204b798eb70c46vandwalle                // As this is a direct user choice, we strongly prefer this configuration,
13092451dbcc4f9641df188326215b204b798eb70c46vandwalle                // hence give +/-100
13102451dbcc4f9641df188326215b204b798eb70c46vandwalle                if ((lastSelectedConfiguration != null)
13112451dbcc4f9641df188326215b204b798eb70c46vandwalle                        && candidate.configKey().equals(lastSelectedConfiguration)) {
13122451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // candidate is the last selected configuration,
13132451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // so keep it above connect choices (+/-60) and
13142451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // above RSSI/scorer based selection of linked configuration (+/- 50)
13152451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // by reducing order by -100
13162451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = order - 100;
13172451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (VDBG)   {
13182451dbcc4f9641df188326215b204b798eb70c46vandwalle                        logDbg("  prefers -100 " + candidate.configKey()
13192451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " over " + config.configKey()
13202451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " because it is the last selected -> "
13212451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + Integer.toString(order));
13222451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
13232451dbcc4f9641df188326215b204b798eb70c46vandwalle                } else if ((lastSelectedConfiguration != null)
13242451dbcc4f9641df188326215b204b798eb70c46vandwalle                        && config.configKey().equals(lastSelectedConfiguration)) {
13252451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // config is the last selected configuration,
13262451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // so keep it above connect choices (+/-60) and
13272451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // above RSSI/scorer based selection of linked configuration (+/- 50)
13282451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // by increasing order by +100
13292451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = order + 100;
13302451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (VDBG)   {
13312451dbcc4f9641df188326215b204b798eb70c46vandwalle                        logDbg("  prefers +100 " + config.configKey()
13322451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " over " + candidate.configKey()
13332451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " because it is the last selected -> "
13342451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + Integer.toString(order));
13352451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
13362451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
13372451dbcc4f9641df188326215b204b798eb70c46vandwalle
1338f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (order > 0) {
1339931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Ascending : candidate < config
1340f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    candidate = config;
1341f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1342f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1343f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1344f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1345c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        // Wait for VPN to be available on the system to make use of this code
13462451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Now, go thru scan result to try finding a better untrusted network
1347f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (mNetworkScoreCache != null) {
1348f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi5 = WifiConfiguration.INVALID_RSSI;
1349f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi24 = WifiConfiguration.INVALID_RSSI;
1350f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            WifiConfiguration.Visibility visibility;
1351f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate != null) {
1352f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi5 = candidate.visibility.rssi5;
1353f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi24 = candidate.visibility.rssi24;
1354f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1355f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1356931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Get current date
13572451dbcc4f9641df188326215b204b798eb70c46vandwalle            long nowMs = System.currentTimeMillis();
1358c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            int currentScore = -10000;
1359c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // The untrusted network with highest score
1360c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            ScanResult untrustedCandidate = null;
13612451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Look for untrusted scored network only if the current candidate is bad
1362c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (isBadCandidate(rssi24, rssi5)) {
1363f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                for (ScanResult result : scanResultCache.values()) {
1364c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    int rssiBoost = 0;
1365c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // We look only at untrusted networks with a valid SSID
1366c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // A trusted result would have been looked at thru it's Wificonfiguration
1367c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    if (TextUtils.isEmpty(result.SSID) || !result.untrusted) {
1368c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        continue;
1369c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    }
13702451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if ((nowMs - result.seen) < 3000) {
1371c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        // Increment usage count for the network
1372c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        mWifiConnectionStatistics.incrementOrAddUntrusted(result.SSID, 0, 1);
1373c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
1374c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        if (lastUntrustedBSSID != null
1375c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                && result.BSSID.equals(lastUntrustedBSSID)) {
1376c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            // Apply a large hysteresis to the untrusted network we are connected to
1377c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            rssiBoost = 25;
1378c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        }
1379c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        int score = mNetworkScoreCache.getNetworkScore(result, rssiBoost);
1380c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        if (score != WifiNetworkScoreCache.INVALID_NETWORK_SCORE
1381c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                && score > currentScore) {
1382c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            // Highest score: Select this candidate
1383c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            currentScore = score;
1384c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            untrustedCandidate = result;
1385c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            if (VDBG) {
1386c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                logDbg("AutoJoinController: found untrusted candidate "
1387c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                        + result.SSID
1388c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                + " RSSI=" + result.level
1389c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                + " freq=" + result.frequency
1390c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                + " score=" + score);
1391c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            }
1392f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        }
1393f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
1394f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1395f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1396c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (untrustedCandidate != null) {
1397c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                if (lastUntrustedBSSID == null
1398c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        || !untrustedCandidate.SSID.equals(lastUntrustedBSSID)) {
1399c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // We found a new candidate that we are going to connect to, then
1400c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // increase its connection count
14018c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    mWifiConnectionStatistics.
14028c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                            incrementOrAddUntrusted(untrustedCandidate.SSID, 1, 0);
1403c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // Remember which SSID we are connecting to
1404c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    lastUntrustedBSSID = untrustedCandidate.SSID;
1405c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                }
1406c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            }
1407c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // Now we don't have VPN, and thus don't actually connect to the untrusted candidate
1408c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            untrustedCandidate = null;
1409c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        }
1410b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
1411931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1412931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         *  If candidate is found, check the state of the connection so as
1413931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         *  to decide if we should be acting on this candidate and switching over
1414931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1415b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        int networkDelta = compareNetwork(candidate);
1416b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (DBG && candidate != null) {
1417b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String doSwitch = "";
1418b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String current = "";
1419b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (networkDelta < 0) {
1420b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                doSwitch = " -> not switching";
1421b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1422b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (currentConfiguration != null) {
1423b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                current = " with current " + currentConfiguration;
1424b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1425b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("attemptAutoJoin networkSwitching candidate "
1426b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                    + candidate.configKey()
1427b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + current
1428c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    + " linked=" + (currentConfiguration != null
1429b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            && currentConfiguration.isLinked(candidate))
1430b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + " : delta="
1431b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + Integer.toString(networkDelta) + " "
1432b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + doSwitch);
1433b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
14344dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1435931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1436931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * Ask WifiStateMachine permission to switch :
1437931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * if user is currently streaming voice traffic,
1438931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * then we should not be allowed to switch regardless of the delta
1439931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1440b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (mWifiStateMachine.shouldSwitchNetwork(networkDelta)) {
1441b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (mStaStaSupported) {
1442b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("mStaStaSupported --> error do nothing now ");
1443b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            } else {
1444b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (currentConfiguration != null && currentConfiguration.isLinked(candidate)) {
1445b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_EXTENDED_ROAMING;
1446b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                } else {
1447b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_OUT_OF_NETWORK_ROAMING;
1448b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1449b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1450b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto connect with netId "
1451b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(candidate.networkId)
1452b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " to " + candidate.configKey());
1453b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
14542451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (didOverride) {
14552451dbcc4f9641df188326215b204b798eb70c46vandwalle                    candidate.numScorerOverrideAndSwitchedNetwork++;
14562451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
1457c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                candidate.numAssociation++;
1458e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                mWifiConnectionStatistics.numAutoJoinAttempt++;
14599f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
14609f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                // First step we selected the configuration we want to connect to
14619f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                // Second step: Look for the best Scan result for this configuration
14629f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                // TODO this algorithm should really be done in one step
14639f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                String currentBSSID = mWifiStateMachine.getCurrentBSSID();
1464b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                ScanResult roamCandidate = attemptRoam(null, candidate, 3000, null);
14659f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                if (roamCandidate != null && currentBSSID != null
14669f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                        && currentBSSID.equals(roamCandidate.BSSID)) {
1467b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    // Sanity, we were already asociated to that candidate
14689f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    roamCandidate = null;
14699f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                }
1470b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                if (roamCandidate != null && roamCandidate.is5GHz()) {
14719f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    // If the configuration hasn't a default BSSID selected, and the best
14729f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    // candidate is 5GHZ, then select this candidate so as WifiStateMachine and
14739f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    // supplicant will pick it first
14749f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    candidate.BSSID = roamCandidate.BSSID;
14759f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    if (VDBG) {
14769f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                        logDbg("AutoJoinController: lock to 5GHz "
14779f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                                + candidate.SSID
14789f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                                + " RSSI=" + roamCandidate.level
14799f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                                + " freq=" + roamCandidate.frequency);
14809f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    }
14819f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                }
1482b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT,
1483b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                        candidate.networkId, networkSwitchType, candidate);
14844dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
1485b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
14864dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1487b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (networkSwitchType == AUTO_JOIN_IDLE) {
1488e67ec726c07410073575473c0f50dc737629f5davandwalle            String currentBSSID = mWifiStateMachine.getCurrentBSSID();
1489931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Attempt same WifiConfiguration roaming
1490e67ec726c07410073575473c0f50dc737629f5davandwalle            ScanResult roamCandidate = attemptRoam(null, currentConfiguration, 3000,
1491e67ec726c07410073575473c0f50dc737629f5davandwalle                    currentBSSID);
1492e67ec726c07410073575473c0f50dc737629f5davandwalle            /**
1493e67ec726c07410073575473c0f50dc737629f5davandwalle             *  TODO: (post L initial release)
1494e67ec726c07410073575473c0f50dc737629f5davandwalle             *  consider handling linked configurations roaming (i.e. extended Roaming)
1495e67ec726c07410073575473c0f50dc737629f5davandwalle             *  thru the attemptRoam function which makes use of the RSSI roaming threshold.
1496e67ec726c07410073575473c0f50dc737629f5davandwalle             *  At the moment, extended roaming is only handled thru the attemptAutoJoin()
1497e67ec726c07410073575473c0f50dc737629f5davandwalle             *  function which compare configurations.
1498e67ec726c07410073575473c0f50dc737629f5davandwalle             *
1499e67ec726c07410073575473c0f50dc737629f5davandwalle             *  The advantage of making use of attemptRoam function is that this function
1500e67ec726c07410073575473c0f50dc737629f5davandwalle             *  will looks at all the BSSID of each configurations, instead of only looking
1501e67ec726c07410073575473c0f50dc737629f5davandwalle             *  at WifiConfiguration.visibility which keeps trackonly of the RSSI/band of the
1502e67ec726c07410073575473c0f50dc737629f5davandwalle             *  two highest BSSIDs.
1503e67ec726c07410073575473c0f50dc737629f5davandwalle             */
1504e67ec726c07410073575473c0f50dc737629f5davandwalle            // Attempt linked WifiConfiguration roaming
1505e67ec726c07410073575473c0f50dc737629f5davandwalle            /* if (currentConfiguration != null
1506e67ec726c07410073575473c0f50dc737629f5davandwalle                    && currentConfiguration.linkedConfigurations != null) {
1507e67ec726c07410073575473c0f50dc737629f5davandwalle                for (String key : currentConfiguration.linkedConfigurations.keySet()) {
1508e67ec726c07410073575473c0f50dc737629f5davandwalle                    WifiConfiguration link = mWifiConfigStore.getWifiConfiguration(key);
1509e67ec726c07410073575473c0f50dc737629f5davandwalle                    if (link != null) {
1510e67ec726c07410073575473c0f50dc737629f5davandwalle                        roamCandidate = attemptRoam(roamCandidate, link, 3000,
1511e67ec726c07410073575473c0f50dc737629f5davandwalle                                currentBSSID);
1512e67ec726c07410073575473c0f50dc737629f5davandwalle                    }
1513e67ec726c07410073575473c0f50dc737629f5davandwalle                }
1514e67ec726c07410073575473c0f50dc737629f5davandwalle            }*/
1515e67ec726c07410073575473c0f50dc737629f5davandwalle            if (roamCandidate != null && currentBSSID != null
1516e67ec726c07410073575473c0f50dc737629f5davandwalle                    && currentBSSID.equals(roamCandidate.BSSID)) {
1517e67ec726c07410073575473c0f50dc737629f5davandwalle                roamCandidate = null;
1518e67ec726c07410073575473c0f50dc737629f5davandwalle            }
1519b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (roamCandidate != null) {
1520b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1521b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto roam with netId "
1522b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(currentConfiguration.networkId)
1523b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " " + currentConfiguration.configKey() + " to BSSID="
1524b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + roamCandidate.BSSID + " freq=" + roamCandidate.frequency
1525b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " RSSI=" + roamCandidate.frequency);
1526b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1527b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                networkSwitchType = AUTO_JOIN_ROAMING;
1528e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                mWifiConnectionStatistics.numAutoRoamAttempt++;
1529e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle
1530b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_ROAM,
1531b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                            currentConfiguration.networkId, 1, roamCandidate);
1532f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1533f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1534b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (VDBG) logDbg("Done attemptAutoJoin status=" + Integer.toString(networkSwitchType));
1535f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
1536f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle}
1537f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1538