WifiAutoJoinController.java revision 0510c350db16f6bd2930f0a5ace483efbfa681d5
1f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle/*
262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle * Copyright (C) 2014 The Android Open Source Project
3f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
4f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * Licensed under the Apache License, Version 2.0 (the "License");
5f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * you may not use this file except in compliance with the License.
6f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * You may obtain a copy of the License at
7f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
8f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *      http://www.apache.org/licenses/LICENSE-2.0
9f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
10f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * Unless required by applicable law or agreed to in writing, software
11f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * distributed under the License is distributed on an "AS IS" BASIS,
12f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * See the License for the specific language governing permissions and
14f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * limitations under the License.
15f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle */
16f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
17f22d23092ab37286a5ef9d257d5bb32c421d2669vandwallepackage com.android.server.wifi;
18f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
19f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.content.Context;
20f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.NetworkKey;
21f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.NetworkScoreManager;
220c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport android.net.WifiKey;
2377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport android.net.wifi.ScanResult;
2477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport android.net.wifi.WifiConfiguration;
258639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidsonimport android.net.wifi.WifiConfiguration.KeyMgmt;
2677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport android.net.wifi.WifiConnectionStatistics;
27f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalleimport android.os.Process;
2877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport android.provider.Settings;
29c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalleimport android.text.TextUtils;
30f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.util.Log;
31f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
32ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport com.android.server.wifi.anqp.ANQPElement;
33ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport com.android.server.wifi.anqp.Constants;
34ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport com.android.server.wifi.hotspot2.ANQPData;
35ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport com.android.server.wifi.hotspot2.AnqpCache;
36ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport com.android.server.wifi.hotspot2.Chronograph;
37ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport com.android.server.wifi.hotspot2.NetworkDetail;
38ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport com.android.server.wifi.hotspot2.PasspointMatch;
39ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport com.android.server.wifi.hotspot2.PasspointMatchInfo;
40ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport com.android.server.wifi.hotspot2.SupplicantBridge;
41ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport com.android.server.wifi.hotspot2.pps.HomeSP;
42ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
4377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.io.BufferedReader;
4477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.io.IOException;
4577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.io.StringReader;
460c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport java.util.ArrayList;
4777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.util.Arrays;
48d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpandeimport java.util.BitSet;
49ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport java.util.Collection;
50dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalleimport java.util.Collections;
51dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalleimport java.util.Comparator;
52f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.HashMap;
5377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.util.Iterator;
54f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.List;
55ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport java.util.Map;
56f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
57f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle/**
58f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * AutoJoin controller is responsible for WiFi Connect decision
59f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
60f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * It runs in the thread context of WifiStateMachine
61f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
62f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle */
63f22d23092ab37286a5ef9d257d5bb32c421d2669vandwallepublic class WifiAutoJoinController {
64f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
65f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private Context mContext;
66f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiStateMachine mWifiStateMachine;
67f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiConfigStore mWifiConfigStore;
68f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNative mWifiNative;
69f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
70f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private NetworkScoreManager scoreManager;
71f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNetworkScoreCache mNetworkScoreCache;
72f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
73f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final String TAG = "WifiAutoJoinController ";
7431891afce40b903ada9b24ec12e3648ae6aa27b2Jan Nordqvist    private static boolean DBG = false;
75ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean VDBG = false;
76f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final boolean mStaStaSupported = false;
77f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
78c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    public static int mScanResultMaximumAge = 40000; /* milliseconds unit */
79833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle    public static int mScanResultAutoJoinAge = 5000; /* milliseconds unit */
80c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
81453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle    private String mCurrentConfigurationKey = null; //used by autojoin
82f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
8325ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande    private final HashMap<String, ScanDetail> scanResultCache = new HashMap<>();
84f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
85c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    private WifiConnectionStatistics mWifiConnectionStatistics;
86c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
87dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle    /**
88dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * Whether to allow connections to untrusted networks.
89dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     */
908639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    private boolean mAllowUntrustedConnections = false;
918639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
92c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    /* For debug purpose only: if the scored override a score */
93c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    boolean didOverride = false;
94c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
95931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Lose the non-auth failure blacklisting after 8 hours
964dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListHardMilli = 1000 * 60 * 60 * 8;
97931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Lose some temporary blacklisting after 30 minutes
984dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListSoftMilli = 1000 * 60 * 30;
9927355a942653264388e909a4276196ee63e57811vandwalle
100dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle    /**
101dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * @see android.provider.Settings.Global#WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS
102dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     */
10316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson    private static final long DEFAULT_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS = 1000 * 60; // 1 minute
10416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
105b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_IDLE = 0;
106b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_ROAMING = 1;
107b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_EXTENDED_ROAMING = 2;
108b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_OUT_OF_NETWORK_ROAMING = 3;
109b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
11097b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle    public static final int HIGH_THRESHOLD_MODIFIER = 5;
11197b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle
11287df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle    public static final int MAX_RSSI_DELTA = 50;
11387df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle
1141ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    // Below are AutoJoin wide parameters indicating if we should be aggressive before joining
1151ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    // weak network. Note that we cannot join weak network that are going to be marked as unanted by
1161ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    // ConnectivityService because this will trigger link flapping.
1171ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    /**
1181ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     * There was a non-blacklisted configuration that we bailed from because of a weak signal
1191ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     */
1201ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    boolean didBailDueToWeakRssi = false;
1211ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    /**
1221ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     * number of time we consecutively bailed out of an eligible network because its signal
1231ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     * was too weak
1241ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     */
1251ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    int weakRssiBailCount = 0;
1261ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle
127f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    WifiAutoJoinController(Context c, WifiStateMachine w, WifiConfigStore s,
128c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                           WifiConnectionStatistics st, WifiNative n) {
129f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mContext = c;
130f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiStateMachine = w;
131f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore = s;
132f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiNative = n;
133f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mNetworkScoreCache = null;
134c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        mWifiConnectionStatistics = st;
13521bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle        scoreManager =
13621bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                (NetworkScoreManager) mContext.getSystemService(Context.NETWORK_SCORE_SERVICE);
137f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager == null)
138f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("Registered scoreManager NULL " + " service " + Context.NETWORK_SCORE_SERVICE);
139f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
140f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager != null) {
141f13817203179f41620514718c8668ae7e418f8afJeff Davidson            mNetworkScoreCache = new WifiNetworkScoreCache(mContext);
142f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            scoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
143f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        } else {
144f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("No network score service: Couldnt register as a WiFi score Manager, type="
145f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(NetworkKey.TYPE_WIFI)
146f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + " service " + Context.NETWORK_SCORE_SERVICE);
147f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            mNetworkScoreCache = null;
148f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
149f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
150f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
151ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    void enableVerboseLogging(int verbose) {
152dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        if (verbose > 0) {
153abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = true;
154ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = true;
155ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        } else {
156abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = false;
157ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = false;
158ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
159ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    }
160ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle
161931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
162931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * Flush out scan results older than mScanResultMaximumAge
163931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
164f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private void ageScanResultsOut(int delay) {
165f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (delay <= 0) {
166931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            delay = mScanResultMaximumAge; // Something sane
167f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
168b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        long milli = System.currentTimeMillis();
169f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
170f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("ageScanResultsOut delay " + Integer.valueOf(delay) + " size "
171f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.valueOf(scanResultCache.size()) + " now " + Long.valueOf(milli));
172f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
173f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
174dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        Iterator<HashMap.Entry<String, ScanDetail>> iter = scanResultCache.entrySet().iterator();
175f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        while (iter.hasNext()) {
176dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            HashMap.Entry<String, ScanDetail> entry = iter.next();
17725ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande            ScanDetail scanDetail = entry.getValue();
17825ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande            if ((scanDetail.getSeen() + delay) < milli) {
179f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                iter.remove();
180f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
181f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
182f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
183f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
184ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
185d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande    void averageRssiAndRemoveFromCache(ScanResult result) {
186d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        // Fetch the previous instance for this result
18725ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande        ScanDetail sd = scanResultCache.get(result.BSSID);
18825ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande        if (sd != null) {
18925ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande            ScanResult sr = sd.getScanResult();
190d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0
191d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                    && result.level == 0
192d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                    && sr.level < -20) {
193d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                // A 'zero' RSSI reading is most likely a chip problem which returns
194d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                // an unknown RSSI, hence ignore it
195d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                result.level = sr.level;
196ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            }
197ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
198d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            // If there was a previous cache result for this BSSID, average the RSSI values
199d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            result.averageRssi(sr.level, sr.seen, mScanResultMaximumAge);
200ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
201d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            // Remove the previous Scan Result - this is not necessary
202d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            scanResultCache.remove(result.BSSID);
203d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        } else if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0 && result.level == 0) {
204d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            // A 'zero' RSSI reading is most likely a chip problem which returns
205d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            // an unknown RSSI, hence initialize it to a sane value
206d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            result.level = mWifiConfigStore.scanResultRssiLevelPatchUp;
207ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        }
208ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    }
209ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
210d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande    void addToUnscoredNetworks(ScanResult result, List<NetworkKey> unknownScanResults) {
211d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        WifiKey wkey;
212d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        // Quoted SSIDs are the only one valid at this stage
213d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        try {
214d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            wkey = new WifiKey("\"" + result.SSID + "\"", result.BSSID);
215d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        } catch (IllegalArgumentException e) {
216d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            logDbg("AutoJoinController: received badly encoded SSID=[" + result.SSID +
217d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                    "] ->skipping this network");
218d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            wkey = null;
219d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        }
220d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        if (wkey != null) {
221d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            NetworkKey nkey = new NetworkKey(wkey);
222d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            //if we don't know this scan result then request a score from the scorer
223d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            unknownScanResults.add(nkey);
224ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        }
225d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        if (VDBG) {
226d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            String cap = "";
227d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            if (result.capabilities != null)
228d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                cap = result.capabilities;
229d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            logDbg(result.SSID + " " + result.BSSID + " rssi="
2300510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle                    + result.level + " cap " + cap + " tsf " + result.timestamp + " is not scored");
231ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        }
232ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    }
233ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
23477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    int addToScanCache(List<ScanDetail> scanList) {
235be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        int numScanResultsKnown = 0; // Record number of scan results we knew about
236be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        WifiConfiguration associatedConfig = null;
2377b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle        boolean didAssociate = false;
2388242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle        long now = System.currentTimeMillis();
239f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
2400c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        ArrayList<NetworkKey> unknownScanResults = new ArrayList<NetworkKey>();
2410c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
242dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        for (ScanDetail scanDetail : scanList) {
24377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            ScanResult result = scanDetail.getScanResult();
2441fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng            if (result.SSID == null) continue;
245c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
2460510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle            // Fetch previous instance
2470510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle            ScanDetail sd = scanResultCache.get(result.BSSID);
2480510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle            if (sd != null) {
2490510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle                ScanResult sr = sd.getScanResult();
2500510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle                if (sr.timestamp != 0 && sr.timestamp == result.timestamp) {
2510510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle                    logDbg(" addToScanCache skip stale " + result.SSID + " " + result.BSSID
2520510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle                            + " tsf=" + result.timestamp + " age=" + (now - result.seen)
2530510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle                            + " seen= " + result.seen + " now=" + now);
2540510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle                    continue;
2550510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle                }
2560510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle            }
2570510c350db16f6bd2930f0a5ace483efbfa681d5Pierre Vandwalle
258c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // Make sure we record the last time we saw this result
25925ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande            scanDetail.setSeen();
260f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
261d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            averageRssiAndRemoveFromCache(result);
262e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle
263e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            if (!mNetworkScoreCache.isScoredNetwork(result)) {
264d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                addToUnscoredNetworks(result, unknownScanResults);
2650c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            } else {
266e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (VDBG) {
2677b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    String cap = "";
2687b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    if (result.capabilities != null)
2697b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                        cap = result.capabilities;
270e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    int score = mNetworkScoreCache.getNetworkScore(result);
271e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg(result.SSID + " " + result.BSSID + " rssi="
2727b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                            + result.level + " cap " + cap + " is scored : " + score);
2730c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                }
274f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
275f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
276e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // scanResultCache.put(result.BSSID, new ScanResult(result));
27725ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande            scanResultCache.put(result.BSSID, scanDetail);
278be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            // Add this BSSID to the scanResultCache of a Saved WifiConfiguration
279d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            didAssociate = mWifiConfigStore.updateSavedNetworkHistory(scanDetail);
280f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
281be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            // If not successful, try to associate this BSSID to an existing Saved WifiConfiguration
2827b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle            if (!didAssociate) {
283be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                // We couldn't associate the scan result to a Saved WifiConfiguration
284c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                // Hence it is untrusted
285c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                result.untrusted = true;
2860d616ef3bf635dff8722e064c0be842676390ed8vandwalle            } else {
2870d616ef3bf635dff8722e064c0be842676390ed8vandwalle                // If the scan result has been blacklisted fir 18 hours -> unblacklist
2880d616ef3bf635dff8722e064c0be842676390ed8vandwalle                if ((now - result.blackListTimestamp) > loseBlackListHardMilli) {
2890d616ef3bf635dff8722e064c0be842676390ed8vandwalle                    result.setAutoJoinStatus(ScanResult.ENABLED);
2900d616ef3bf635dff8722e064c0be842676390ed8vandwalle                }
291f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
2927b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle            if (didAssociate) {
293be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                numScanResultsKnown++;
294dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                result.isAutoJoinCandidate++;
295a0708b09ad17b086c008ab100aec7143d7613c80vandwalle            } else {
296a0708b09ad17b086c008ab100aec7143d7613c80vandwalle                result.isAutoJoinCandidate = 0;
297be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            }
298f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
2990c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
3000c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        if (unknownScanResults.size() != 0) {
3010c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            NetworkKey[] newKeys =
3020c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                    unknownScanResults.toArray(new NetworkKey[unknownScanResults.size()]);
303931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Kick the score manager, we will get updated scores asynchronously
3040c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            scoreManager.requestScores(newKeys);
3050c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        }
306be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        return numScanResultsKnown;
307f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
308f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
309f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void logDbg(String message) {
3100888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle        logDbg(message, false);
311ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    }
312ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
313ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    void logDbg(String message, boolean stackTrace) {
314ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (stackTrace) {
31533f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            Log.d(TAG, message + " stack:"
316ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[2].getMethodName() + " - "
317ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[3].getMethodName() + " - "
318ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[4].getMethodName() + " - "
319ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[5].getMethodName());
320ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        } else {
32133f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            Log.d(TAG, message);
322ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        }
323f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
324f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
325931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Called directly from WifiStateMachine
326be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle    int newSupplicantResults(boolean doAutoJoin) {
327be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        int numScanResultsKnown;
32877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        List<ScanDetail> scanList = mWifiStateMachine.getScanResultsListNoCopyUnsync();
329be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        numScanResultsKnown = addToScanCache(scanList);
330f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(mScanResultMaximumAge);
331be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        if (DBG) {
332be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            logDbg("newSupplicantResults size=" + Integer.valueOf(scanResultCache.size())
333dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    + " known=" + numScanResultsKnown + " "
334dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    + doAutoJoin);
335be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        }
3367806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle        if (doAutoJoin) {
3377806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            attemptAutoJoin();
3387806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle        }
339005c1ef113192f898499a407dd266393a8d6b076vandwalle        mWifiConfigStore.writeKnownNetworkHistory(false);
340be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        return numScanResultsKnown;
341f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
342f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
343f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
344931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
345931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * Not used at the moment
346f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * should be a call back from WifiScanner HAL ??
347f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * this function is not hooked and working yet, it will receive scan results from WifiScanners
348f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * with the list of IEs,then populate the capabilities by parsing the IEs and inject the scan
349f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * results as normal.
350f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     */
351f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void newHalScanResults() {
35277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        List<ScanDetail> scanList = null;//mWifiScanner.syncGetScanResultsList();
353f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String akm = WifiParser.parse_akm(null, null);
354f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        logDbg(akm);
355f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        addToScanCache(scanList);
356f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(0);
357f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
358005c1ef113192f898499a407dd266393a8d6b076vandwalle        mWifiConfigStore.writeKnownNetworkHistory(false);
359f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
360f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
361931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
362dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * network link quality changed, called directly from WifiTrafficPoller,
363931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * or by listening to Link Quality intent
364931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
365f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void linkQualitySignificantChange() {
366f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
367f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
368f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
369931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
370f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * compare a WifiConfiguration against the current network, return a delta score
371f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * If not associated, and the candidate will always be better
372f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * For instance if the candidate is a home network versus an unknown public wifi,
373f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * the delta will be infinite, else compare Kepler scores etc…
374b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * Negatve return values from this functions are meaningless per se, just trying to
37521d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle     * keep t````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````hem distinct for debug purpose (i.e. -1, -2 etc...)
376931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
377e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle    private int compareNetwork(WifiConfiguration candidate,
378e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                               String lastSelectedConfiguration) {
379b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (candidate == null)
380b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -3;
381b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
382f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration currentNetwork = mWifiStateMachine.getCurrentWifiConfiguration();
383b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentNetwork == null) {
384c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // Return any absurdly high score, if we are not connected there is no current
385c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // network to...
386dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            return 1000;
387b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
388f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
389f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (candidate.configKey(true).equals(currentNetwork.configKey(true))) {
390b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -2;
391f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
392f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
393b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle        if (DBG) {
394e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            logDbg("compareNetwork will compare " + candidate.configKey()
395e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    + " with current " + currentNetwork.configKey());
396b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle        }
397833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        int order = compareWifiConfigurations(currentNetwork, candidate);
398e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle
399e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // The lastSelectedConfiguration is the configuration the user has manually selected
400e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // thru WifiPicker, or that a 3rd party app asked us to connect to via the
401e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // enableNetwork with disableOthers=true WifiManager API
402e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // As this is a direct user choice, we strongly prefer this configuration,
403e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // hence give +/-100
404e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        if ((lastSelectedConfiguration != null)
405e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                && currentNetwork.configKey().equals(lastSelectedConfiguration)) {
406e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // currentNetwork is the last selected configuration,
407e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // so keep it above connect choices (+/-60) and
408e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // above RSSI/scorer based selection of linked configuration (+/- 50)
409e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // by reducing order by -100
410e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            order = order - 100;
411dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            if (VDBG) {
412e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("     ...and prefers -100 " + currentNetwork.configKey()
413e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " over " + candidate.configKey()
414e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " because it is the last selected -> "
415e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + Integer.toString(order));
416e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            }
417e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        } else if ((lastSelectedConfiguration != null)
418e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                && candidate.configKey().equals(lastSelectedConfiguration)) {
419e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // candidate is the last selected configuration,
420e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // so keep it above connect choices (+/-60) and
421e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // above RSSI/scorer based selection of linked configuration (+/- 50)
422e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // by increasing order by +100
423e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            order = order + 100;
424dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            if (VDBG) {
425e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("     ...and prefers +100 " + candidate.configKey()
426e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " over " + currentNetwork.configKey()
427e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " because it is the last selected -> "
428e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + Integer.toString(order));
429e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            }
430e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        }
431e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle
432ede507649471f1113e9e1919812115ca5a6bc0c8vandwalle        return order;
433f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
434f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
435ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    /**
436ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * update the network history fields fo that configuration
437ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if userTriggered, we mark the configuration as "non selfAdded" since the user has seen it
438ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * and took over management
439ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if it is a "connect", remember which network were there at the point of the connect, so
440ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * as those networks get a relative lower score than the selected configuration
44162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle     *
442ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param netId
443ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param userTriggered : if the update come from WiFiManager
444dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * @param connect       : if the update includes a connect
445931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
44662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle    public void updateConfigurationHistory(int netId, boolean userTriggered, boolean connect) {
447f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration selected = mWifiConfigStore.getWifiConfiguration(netId);
448f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (selected == null) {
449c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory nid=" + netId + " no selected configuration!");
450f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return;
451f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
452f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
453e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        if (selected.SSID == null) {
454c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory nid=" + netId +
455c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    " no SSID in selected configuration!");
456e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            return;
457e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        }
458e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
45962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        if (userTriggered) {
460931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Reenable autojoin for this network,
46162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            // since the user want to connect to this configuration
46227355a942653264388e909a4276196ee63e57811vandwalle            selected.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
46362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            selected.selfAdded = false;
464e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            selected.dirty = true;
46562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        }
466f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
467992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (DBG && userTriggered) {
468f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (selected.connectChoices != null) {
469ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
470f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + Integer.toString(netId) + " now: "
471992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(selected.connectChoices.size())
472992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
473f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
474ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
475992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(netId)
476992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
477f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
478f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
479f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
480ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (connect && userTriggered) {
481ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            boolean found = false;
4822451dbcc4f9641df188326215b204b798eb70c46vandwalle            int choice = 0;
483c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            int size = 0;
4849f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
4859f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // Reset the triggered disabled count, because user wanted to connect to this
4869f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // configuration, and we were not.
4879f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableLowRSSI = 0;
4889f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableBadRSSI = 0;
4899f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableNotHighRSSI = 0;
4909f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredJoinAttempts++;
4919f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
49262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            List<WifiConfiguration> networks =
49362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    mWifiConfigStore.getRecentConfiguredNetworks(12000, false);
494c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (networks != null) size = networks.size();
495c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory found " + size + " networks");
49662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            if (networks != null) {
49762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                for (WifiConfiguration config : networks) {
498992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    if (DBG) {
499992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        logDbg("updateConfigurationHistory got " + config.SSID + " nid="
500992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                                + Integer.toString(config.networkId));
501992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    }
502f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
50362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (selected.configKey(true).equals(config.configKey(true))) {
504ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        found = true;
50562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        continue;
50662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
507f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
50887df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle                    // If the selection was made while config was visible with reasonably good RSSI
50987df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle                    // then register the user preference, else ignore
51087df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle                    if (config.visibility == null ||
51187df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle                            (config.visibility.rssi24 < mWifiConfigStore.thresholdBadRssi24.get()
51287df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle                            && config.visibility.rssi5 < mWifiConfigStore.thresholdBadRssi5.get())
51387df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle                    ) {
51487df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle                        continue;
51562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
516f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
51787df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle                    choice = MAX_RSSI_DELTA + 10; // Make sure the choice overrides the RSSI diff
51887df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle
519931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // The selected configuration was preferred over a recently seen config
520931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // hence remember the user's choice:
521931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // add the recently seen config to the selected's connectChoices array
522ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
523ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    if (selected.connectChoices == null) {
524ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        selected.connectChoices = new HashMap<String, Integer>();
525ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    }
526ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
527ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    logDbg("updateConfigurationHistory add a choice " + selected.configKey(true)
5280888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                            + " over " + config.configKey(true)
5292451dbcc4f9641df188326215b204b798eb70c46vandwalle                            + " choice " + Integer.toString(choice));
530cf5b8eb8a08c45bd4a82f1f4bb789c8a1b08744fvandwalle
5312f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // Add the visible config to the selected's connect choice list
5322f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    selected.connectChoices.put(config.configKey(true), choice);
533f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
53462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (config.connectChoices != null) {
535ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        if (VDBG) {
536ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                            logDbg("updateConfigurationHistory will remove "
53762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                    + selected.configKey(true) + " from " + config.configKey(true));
538ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        }
539931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Remove the selected from the recently seen config's connectChoice list
54062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        config.connectChoices.remove(selected.configKey(true));
5410888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle
5420888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        if (selected.linkedConfigurations != null) {
543dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                            // Remove the selected's linked configuration from the
544dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                            // recently seen config's connectChoice list
545dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                            for (String key : selected.linkedConfigurations.keySet()) {
546dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                                config.connectChoices.remove(key);
547dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                            }
5480888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        }
54962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
550ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                }
551ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                if (found == false) {
552dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    // We haven't found the configuration that the user just selected in our
553dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    // scan cache.
554dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    // In that case we will need a new scan before attempting to connect to this
555dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    // configuration anyhow and thus we can process the scan results then.
556dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    logDbg("updateConfigurationHistory try to connect to an old network!! : "
557dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                            + selected.configKey());
55862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
559f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
56062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                if (selected.connectChoices != null) {
56162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (VDBG)
562ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        logDbg("updateConfigurationHistory " + Integer.toString(netId)
56362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                + " now: " + Integer.toString(selected.connectChoices.size()));
56462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
565f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
566f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
567992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle
568931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // TODO: write only if something changed
569992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (userTriggered || connect) {
570005c1ef113192f898499a407dd266393a8d6b076vandwalle            mWifiConfigStore.writeKnownNetworkHistory(false);
571992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        }
572f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
573f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
57421d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle    int getConnectChoice(WifiConfiguration source, WifiConfiguration target, boolean strict) {
57521d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle        int choice = 0;
5762451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (source == null || target == null) {
5772451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
578f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
579f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
5802451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (source.connectChoices != null
5812451dbcc4f9641df188326215b204b798eb70c46vandwalle                && source.connectChoices.containsKey(target.configKey(true))) {
582a20305612380c956fa84b1e80523eb7719f62fd1Pierre Vandwalle            Integer val = source.connectChoices.get(target.configKey(true));
583a20305612380c956fa84b1e80523eb7719f62fd1Pierre Vandwalle            if (val != null) {
584a20305612380c956fa84b1e80523eb7719f62fd1Pierre Vandwalle                choice = val;
585a20305612380c956fa84b1e80523eb7719f62fd1Pierre Vandwalle            }
5862451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else if (source.linkedConfigurations != null) {
587f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            for (String key : source.linkedConfigurations.keySet()) {
588f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(key);
589f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (config != null) {
590f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (config.connectChoices != null) {
591a20305612380c956fa84b1e80523eb7719f62fd1Pierre Vandwalle                        Integer val = config.connectChoices.get(target.configKey(true));
592a20305612380c956fa84b1e80523eb7719f62fd1Pierre Vandwalle                        if (val != null) {
593a20305612380c956fa84b1e80523eb7719f62fd1Pierre Vandwalle                            choice = val;
594a20305612380c956fa84b1e80523eb7719f62fd1Pierre Vandwalle                        }
595f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
596f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
597f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
5982451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
5992451dbcc4f9641df188326215b204b798eb70c46vandwalle
60021d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle        if (!strict && choice == 0) {
60133f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            // We didn't find the connect choice; fallback to some default choices
60233f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            int sourceScore = getSecurityScore(source);
60333f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            int targetScore = getSecurityScore(target);
6048eefaf2c281b44fb7a4d951ba587f447800c4b4fVinit Deshpande            choice = sourceScore - targetScore;
60533f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande        }
60633f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande
60733f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande        return choice;
6082451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
6092451dbcc4f9641df188326215b204b798eb70c46vandwalle
61033f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande    int compareWifiConfigurationsFromVisibility(WifiConfiguration.Visibility a, int aRssiBoost,
611dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                                                String dbgA, WifiConfiguration.Visibility b, int bRssiBoost, String dbgB) {
6122451dbcc4f9641df188326215b204b798eb70c46vandwalle
613815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        int aRssiBoost5 = 0; // 5GHz RSSI boost to apply for purpose band selection (5GHz pref)
614815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        int bRssiBoost5 = 0; // 5GHz RSSI boost to apply for purpose band selection (5GHz pref)
615815788ba7838fc54310baed3deb9b95548e0ce69vandwalle
616815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        int aScore = 0;
617815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        int bScore = 0;
618815788ba7838fc54310baed3deb9b95548e0ce69vandwalle
619815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        boolean aPrefers5GHz = false;
620815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        boolean bPrefers5GHz = false;
6214dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
6222451dbcc4f9641df188326215b204b798eb70c46vandwalle        /**
623815788ba7838fc54310baed3deb9b95548e0ce69vandwalle         * Calculate a boost to apply to RSSI value of configuration we want to join on 5GHz:
624815788ba7838fc54310baed3deb9b95548e0ce69vandwalle         * Boost RSSI value of 5GHz bands iff the base value is better than threshold,
625815788ba7838fc54310baed3deb9b95548e0ce69vandwalle         * penalize the RSSI value of 5GHz band iff the base value is lower than threshold
6262451dbcc4f9641df188326215b204b798eb70c46vandwalle         * This implements band preference where we prefer 5GHz if RSSI5 is good enough, whereas
6272451dbcc4f9641df188326215b204b798eb70c46vandwalle         * we prefer 2.4GHz otherwise.
6282451dbcc4f9641df188326215b204b798eb70c46vandwalle         */
62933f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande        aRssiBoost5 = rssiBoostFrom5GHzRssi(a.rssi5, dbgA + "->");
63033f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande        bRssiBoost5 = rssiBoostFrom5GHzRssi(b.rssi5, dbgB + "->");
6312451dbcc4f9641df188326215b204b798eb70c46vandwalle
632815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // Select which band to use for a
63333f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande        if (a.rssi5 + aRssiBoost5 > a.rssi24) {
6342451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Prefer a's 5GHz
635815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            aPrefers5GHz = true;
636815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        }
637815788ba7838fc54310baed3deb9b95548e0ce69vandwalle
638815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // Select which band to use for b
63933f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande        if (b.rssi5 + bRssiBoost5 > b.rssi24) {
640815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            // Prefer b's 5GHz
641815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            bPrefers5GHz = true;
642815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        }
643815788ba7838fc54310baed3deb9b95548e0ce69vandwalle
644815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        if (aPrefers5GHz) {
645815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            if (bPrefers5GHz) {
646815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // If both a and b are on 5GHz then we don't apply the 5GHz RSSI boost to either
647815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // one, but directly compare the RSSI values, this improves stability,
648815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // since the 5GHz RSSI boost can introduce large fluctuations
64933f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande                aScore = a.rssi5 + aRssiBoost;
650815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            } else {
651815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // If only a is on 5GHz, then apply the 5GHz preference boost to a
65233f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande                aScore = a.rssi5 + aRssiBoost + aRssiBoost5;
653815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            }
6542451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else {
65533f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            aScore = a.rssi24 + aRssiBoost;
656f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
6572451dbcc4f9641df188326215b204b798eb70c46vandwalle
658815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        if (bPrefers5GHz) {
659815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            if (aPrefers5GHz) {
660815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // If both a and b are on 5GHz then we don't apply the 5GHz RSSI boost to either
661815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // one, but directly compare the RSSI values, this improves stability,
662815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // since the 5GHz RSSI boost can introduce large fluctuations
66333f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande                bScore = b.rssi5 + bRssiBoost;
664815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            } else {
665815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // If only b is on 5GHz, then apply the 5GHz preference boost to b
66633f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande                bScore = b.rssi5 + bRssiBoost + bRssiBoost5;
667815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            }
668815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        } else {
66933f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            bScore = b.rssi24 + bRssiBoost;
670815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        }
67133f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande
672815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        if (VDBG) {
67333f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            logDbg("        " + dbgA + " is5=" + aPrefers5GHz + " score=" + aScore
67433f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande                    + " " + dbgB + " is5=" + bPrefers5GHz + " score=" + bScore);
675815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        }
676f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle
677f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        // Debug only, record RSSI comparison parameters
67833f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande        if (a != null) {
67933f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            a.score = aScore;
68033f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            a.currentNetworkBoost = aRssiBoost;
68133f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            a.bandPreferenceBoost = aRssiBoost5;
682f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        }
68333f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande        if (b != null) {
68433f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            b.score = bScore;
68533f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            b.currentNetworkBoost = bRssiBoost;
68633f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande            b.bandPreferenceBoost = bRssiBoost5;
687f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        }
688f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle
689815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // Compare a and b
690815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // If a score is higher then a > b and the order is descending (negative)
691815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // If b score is higher then a < b and the order is ascending (positive)
692815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        return bScore - aScore;
693f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
694f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
6952451dbcc4f9641df188326215b204b798eb70c46vandwalle    // Compare WifiConfiguration by RSSI, and return a comparison value in the range [-50, +50]
6962451dbcc4f9641df188326215b204b798eb70c46vandwalle    // The result represents "approximately" an RSSI difference measured in dBM
6972451dbcc4f9641df188326215b204b798eb70c46vandwalle    // Adjusted with various parameters:
6982451dbcc4f9641df188326215b204b798eb70c46vandwalle    // +) current network gets a +15 boost
6992451dbcc4f9641df188326215b204b798eb70c46vandwalle    // +) 5GHz signal, if they are strong enough, get a +15 or +25 boost, representing the
7002451dbcc4f9641df188326215b204b798eb70c46vandwalle    // fact that at short range we prefer 5GHz band as it is cleaner of interference and
7012451dbcc4f9641df188326215b204b798eb70c46vandwalle    // provides for wider channels
7022451dbcc4f9641df188326215b204b798eb70c46vandwalle    int compareWifiConfigurationsRSSI(WifiConfiguration a, WifiConfiguration b,
7032451dbcc4f9641df188326215b204b798eb70c46vandwalle                                      String currentConfiguration) {
704f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
7052451dbcc4f9641df188326215b204b798eb70c46vandwalle
7062451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Boost used so as to favor current config
7072451dbcc4f9641df188326215b204b798eb70c46vandwalle        int aRssiBoost = 0;
7082451dbcc4f9641df188326215b204b798eb70c46vandwalle        int bRssiBoost = 0;
7092451dbcc4f9641df188326215b204b798eb70c46vandwalle
7102451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Retrieve the visibility
711f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility astatus = a.visibility;
712f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility bstatus = b.visibility;
713f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (astatus == null || bstatus == null) {
7142451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Error visibility wasn't set
715b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurations NULL band status!");
716f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 0;
717f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
7182451dbcc4f9641df188326215b204b798eb70c46vandwalle
7192451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply Hysteresis, boost RSSI of current configuration
7202451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (null != currentConfiguration) {
7212451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (a.configKey().equals(currentConfiguration)) {
72293a1fddee50a244d31036cddae6b7db6630fd93dvandwalle                aRssiBoost = mWifiConfigStore.currentNetworkBoost;
7232451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (b.configKey().equals(currentConfiguration)) {
72493a1fddee50a244d31036cddae6b7db6630fd93dvandwalle                bRssiBoost = mWifiConfigStore.currentNetworkBoost;
7252451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
7262451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
7272451dbcc4f9641df188326215b204b798eb70c46vandwalle
728dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        if (VDBG) {
729b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsRSSI: " + a.configKey()
730dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                            + " rssi=" + Integer.toString(astatus.rssi24)
731dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                            + "," + Integer.toString(astatus.rssi5)
732dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                            + " boost=" + Integer.toString(aRssiBoost)
733dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                            + " " + b.configKey() + " rssi="
734dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                            + Integer.toString(bstatus.rssi24) + ","
735dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                            + Integer.toString(bstatus.rssi5)
736dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                            + " boost=" + Integer.toString(bRssiBoost)
7372451dbcc4f9641df188326215b204b798eb70c46vandwalle            );
738f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
7392451dbcc4f9641df188326215b204b798eb70c46vandwalle
74033f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande        order = compareWifiConfigurationsFromVisibility(
74133f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande                a.visibility, aRssiBoost, a.configKey(),
74233f9ad2442844df078dde3ae67961e7132a8a48dVinit Deshpande                b.visibility, bRssiBoost, b.configKey());
7432451dbcc4f9641df188326215b204b798eb70c46vandwalle
74487df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle        // Normalize the order to [-50, +50] = [ -MAX_RSSI_DELTA, MAX_RSSI_DELTA]
74587df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle        if (order > MAX_RSSI_DELTA) order = MAX_RSSI_DELTA;
74687df79e235c64f7062d0c50658fe1999b1225435Pierre Vandwalle        else if (order < -MAX_RSSI_DELTA) order = -MAX_RSSI_DELTA;
7472451dbcc4f9641df188326215b204b798eb70c46vandwalle
7482451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
7492451dbcc4f9641df188326215b204b798eb70c46vandwalle            String prefer = " = ";
7502451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (order > 0) {
7512451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " < "; // Ascending
7522451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (order < 0) {
7532451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " > "; // Descending
7542451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
755b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsRSSI " + a.configKey()
7562451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + a.visibility.rssi24
7572451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.rssi5
7582451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + a.visibility.num24
7592451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.num5 + ")"
7602451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + prefer + b.configKey()
7612451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + b.visibility.rssi24
7622451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.rssi5
7632451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + b.visibility.num24
7642451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.num5 + ")"
7652451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " -> " + order);
7662451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
7672451dbcc4f9641df188326215b204b798eb70c46vandwalle
768f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
769f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
770f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
771833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle    /**
772833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle     * b/18490330 only use scorer for untrusted networks
773dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * <p/>
774dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * int compareWifiConfigurationsWithScorer(WifiConfiguration a, WifiConfiguration b) {
775dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * <p/>
776dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * boolean aIsActive = false;
777dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * boolean bIsActive = false;
778dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * <p/>
779dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * // Apply Hysteresis : boost RSSI of current configuration before
780dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * // looking up the score
781dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * if (null != mCurrentConfigurationKey) {
782dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * if (a.configKey().equals(mCurrentConfigurationKey)) {
783dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * aIsActive = true;
784dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * } else if (b.configKey().equals(mCurrentConfigurationKey)) {
785dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * bIsActive = true;
786dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * }
787dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * }
788dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * int scoreA = getConfigNetworkScore(a, mScanResultAutoJoinAge, aIsActive);
789dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * int scoreB = getConfigNetworkScore(b, mScanResultAutoJoinAge, bIsActive);
790dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * <p/>
791dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * // Both configurations need to have a score for the scorer to be used
792dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * // ...and the scores need to be different:-)
793dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * if (scoreA == WifiNetworkScoreCache.INVALID_NETWORK_SCORE
794dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * || scoreB == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
795dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * if (VDBG)  {
796dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * logDbg("    compareWifiConfigurationsWithScorer no-scores: "
797dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + a.configKey()
798dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + " "
799dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + b.configKey());
800dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * }
801dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * return 0;
802dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * }
803dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * <p/>
804dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * if (VDBG) {
805dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * String prefer = " = ";
806dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * if (scoreA < scoreB) {
807dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * prefer = " < ";
808dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * } if (scoreA > scoreB) {
809dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * prefer = " > ";
810dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * }
811dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * logDbg("    compareWifiConfigurationsWithScorer " + a.configKey()
812dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + " rssi=(" + a.visibility.rssi24
813dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + "," + a.visibility.rssi5
814dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + ") num=(" + a.visibility.num24
815dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + "," + a.visibility.num5 + ")"
816dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + " sc=" + scoreA
817dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + prefer + b.configKey()
818dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + " rssi=(" + b.visibility.rssi24
819dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + "," + b.visibility.rssi5
820dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + ") num=(" + b.visibility.num24
821dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + "," + b.visibility.num5 + ")"
822dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + " sc=" + scoreB
823dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * + " -> " + Integer.toString(scoreB - scoreA));
824dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * }
825dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * <p/>
826dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * // If scoreA > scoreB, the comparison is descending hence the return value is negative
827dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * return scoreB - scoreA;
828dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * }
829833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle     */
8302451dbcc4f9641df188326215b204b798eb70c46vandwalle
831d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande    int getSecurityScore(WifiConfiguration config) {
832d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande
833d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        if (TextUtils.isEmpty(config.SSID) == false) {
834d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP)
835d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                    || config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)
836d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                    || config.allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
837d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                /* enterprise or PSK networks get highest score */
838d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                return 100;
839d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            } else if (config.allowedKeyManagement.get(KeyMgmt.NONE)) {
840d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                /* open networks have lowest score */
841d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                return 33;
842d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            }
843d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        } else if (TextUtils.isEmpty(config.FQDN) == false) {
844d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            /* passpoint networks have medium preference */
845d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            return 66;
846d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        }
847d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande
848d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        /* bad network */
849d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        return 0;
850d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande    }
851d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande
852f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    int compareWifiConfigurations(WifiConfiguration a, WifiConfiguration b) {
853f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
854f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        boolean linked = false;
855f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
856453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if ((a.linkedConfigurations != null) && (b.linkedConfigurations != null)
857453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (a.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)
858453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (b.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)) {
8592451dbcc4f9641df188326215b204b798eb70c46vandwalle            if ((a.linkedConfigurations.get(b.configKey(true)) != null)
8602451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && (b.linkedConfigurations.get(a.configKey(true)) != null)) {
861f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                linked = true;
862f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
863f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
864f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
865f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (a.ephemeral && b.ephemeral == false) {
866f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
867b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurations ephemeral and prefers " + b.configKey()
868453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + a.configKey());
869f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
870931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            return 1; // b is of higher priority - ascending
871f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
872f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (b.ephemeral && a.ephemeral == false) {
873f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
874b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurations ephemeral and prefers " + a.configKey()
875453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey());
876f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
877931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            return -1; // a is of higher priority - descending
878f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
879f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
8802451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply RSSI, in the range [-5, +5]
8812451dbcc4f9641df188326215b204b798eb70c46vandwalle        // after band adjustment, +n difference roughly corresponds to +10xn dBm
8822451dbcc4f9641df188326215b204b798eb70c46vandwalle        order = order + compareWifiConfigurationsRSSI(a, b, mCurrentConfigurationKey);
883f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
8842451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If the configurations are not linked, compare by user's choice, only a
8852451dbcc4f9641df188326215b204b798eb70c46vandwalle        // very high RSSI difference can then override the choice
8862451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (!linked) {
8872451dbcc4f9641df188326215b204b798eb70c46vandwalle            int choice;
888f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
88921d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle            choice = getConnectChoice(a, b, false);
8902451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice > 0) {
891931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of higher priority - descending
8922451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = order - choice;
893f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG) {
894b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers " + a.configKey()
895453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + " over " + b.configKey()
896b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " due to user choice of " + choice
897b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " order -> " + Integer.toString(order));
898f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
899f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                if (a.visibility != null) {
900f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    a.visibility.lastChoiceBoost = choice;
901f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    a.visibility.lastChoiceConfig = b.configKey();
902f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                }
9032451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
9042451dbcc4f9641df188326215b204b798eb70c46vandwalle
90521d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle            choice = getConnectChoice(b, a, false);
9062451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice > 0) {
907931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of lower priority - ascending
9082451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = order + choice;
9094dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                if (VDBG) {
910b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers " + b.configKey() + " over "
911b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + a.configKey() + " due to user choice of " + choice
912b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " order ->" + Integer.toString(order));
913f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
914f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                if (b.visibility != null) {
915f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    b.visibility.lastChoiceBoost = choice;
916f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    b.visibility.lastChoiceConfig = a.configKey();
917f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                }
918f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
919f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
920ede1310be531a84faa08f02c3fd243448dd936ddvandwalle
921f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order == 0) {
922931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // We don't know anything - pick the last seen i.e. K behavior
923931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // we should do this only for recently picked configurations
924f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (a.priority > b.priority) {
925931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of higher priority - descending
9262451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (VDBG) {
927b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers -1 " + a.configKey() + " over "
928453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + b.configKey() + " due to priority");
929f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
930f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
931f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                order = -1;
932f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else if (a.priority < b.priority) {
933931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of lower priority - ascending
9342451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (VDBG) {
935b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers +1 " + b.configKey() + " over "
936453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + a.configKey() + " due to priority");
937f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
9382451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = 1;
939f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
940f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
941f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
942f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String sorder = " == ";
943931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        if (order > 0) {
944f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " < ";
945931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        } else if (order < 0) {
946f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " > ";
947931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        }
948f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
9492451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
950b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("compareWifiConfigurations: " + a.configKey() + sorder
951453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    + b.configKey() + " order " + Integer.toString(order));
952f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
953f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
954f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
955f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
956f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
957c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    boolean isBadCandidate(int rssi5, int rssi24) {
958c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        return (rssi5 < -80 && rssi24 < -90);
959c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    }
960c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
961833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle    /*
962c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    int compareWifiConfigurationsTop(WifiConfiguration a, WifiConfiguration b) {
963c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        int scorerOrder = compareWifiConfigurationsWithScorer(a, b);
964c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        int order = compareWifiConfigurations(a, b);
965c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
966c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        if (scorerOrder * order < 0) {
967b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (VDBG) {
968b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    -> compareWifiConfigurationsTop: " +
969b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                        "scorer override " + scorerOrder + " " + order);
970b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
971c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // For debugging purpose, remember that an override happened
972c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // during that autojoin Attempt
973c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            didOverride = true;
974c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            a.numScorerOverride++;
975c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            b.numScorerOverride++;
976c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        }
977c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
978c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        if (scorerOrder != 0) {
979c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // If the scorer came up with a result then use the scorer's result, else use
980c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // the order provided by the base comparison function
981c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            order = scorerOrder;
982c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        }
983c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        return order;
984c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    }
985833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle    */
986c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
9879f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle    public int rssiBoostFrom5GHzRssi(int rssi, String dbg) {
9880eebae7334d6129f7ca1344e4b20199794994358vandwalle        if (!mWifiConfigStore.enable5GHzPreference) {
9890eebae7334d6129f7ca1344e4b20199794994358vandwalle            return 0;
9900eebae7334d6129f7ca1344e4b20199794994358vandwalle        }
991e67ec726c07410073575473c0f50dc737629f5davandwalle        if (rssi
99277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                > mWifiConfigStore.bandPreferenceBoostThreshold5.get()) {
993e67ec726c07410073575473c0f50dc737629f5davandwalle            // Boost by 2 dB for each point
994e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Start boosting at -65
995e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Boost by 20 if above -55
996e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Boost by 40 if abore -45
9970eebae7334d6129f7ca1344e4b20199794994358vandwalle            int boost = mWifiConfigStore.bandPreferenceBoostFactor5
998dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    * (rssi - mWifiConfigStore.bandPreferenceBoostThreshold5.get());
999e67ec726c07410073575473c0f50dc737629f5davandwalle            if (boost > 50) {
1000815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // 50 dB boost allows jumping from 2.4 to 5GHz
1001e67ec726c07410073575473c0f50dc737629f5davandwalle                // consistently
1002e67ec726c07410073575473c0f50dc737629f5davandwalle                boost = 50;
1003e67ec726c07410073575473c0f50dc737629f5davandwalle            }
10049f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            if (VDBG && dbg != null) {
1005f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                logDbg("        " + dbg + ":    rssi5 " + rssi + " 5GHz-boost " + boost);
10069f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            }
1007e67ec726c07410073575473c0f50dc737629f5davandwalle            return boost;
1008e67ec726c07410073575473c0f50dc737629f5davandwalle        }
1009e67ec726c07410073575473c0f50dc737629f5davandwalle
1010e67ec726c07410073575473c0f50dc737629f5davandwalle        if (rssi
101177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                < mWifiConfigStore.bandPreferencePenaltyThreshold5.get()) {
10120eebae7334d6129f7ca1344e4b20199794994358vandwalle            // penalize if < -75
10130eebae7334d6129f7ca1344e4b20199794994358vandwalle            int boost = mWifiConfigStore.bandPreferencePenaltyFactor5
1014dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    * (rssi - mWifiConfigStore.bandPreferencePenaltyThreshold5.get());
10150eebae7334d6129f7ca1344e4b20199794994358vandwalle            return boost;
1016e67ec726c07410073575473c0f50dc737629f5davandwalle        }
1017e67ec726c07410073575473c0f50dc737629f5davandwalle        return 0;
1018e67ec726c07410073575473c0f50dc737629f5davandwalle    }
1019dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle
1020dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle    /**
1021dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * attemptRoam() function implements the core of the same SSID switching algorithm
1022dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * <p/>
1023dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * Run thru all recent scan result of a WifiConfiguration and select the
1024dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * best one.
1025dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     */
1026e67ec726c07410073575473c0f50dc737629f5davandwalle    public ScanResult attemptRoam(ScanResult a,
1027e67ec726c07410073575473c0f50dc737629f5davandwalle                                  WifiConfiguration current, int age, String currentBSSID) {
1028b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current == null) {
1029dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            if (VDBG) {
1030b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam not associated");
1031b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
1032e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
10334dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
103425ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande
10354d381bc39f5263effdae73ec99065eb299b806caVinit Deshpande        ScanDetailCache scanDetailCache =
103625ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande                mWifiConfigStore.getScanDetailCache(current);
103725ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande
103825ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande        if (scanDetailCache == null) {
1039dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            if (VDBG) {
1040b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam no scan cache");
1041b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
1042e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
10434dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
104425ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande        if (scanDetailCache.size() > 6) {
1045dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            if (VDBG) {
1046c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptRoam scan cache size "
104725ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande                        + scanDetailCache.size() + " --> bail");
1048b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
1049931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Implement same SSID roaming only for configurations
1050c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            // that have less than 4 BSSIDs
1051e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
10524dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
1053b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
10542f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle        if (current.BSSID != null && !current.BSSID.equals("any")) {
1055dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            if (DBG) {
10562f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                logDbg("attemptRoam() BSSID is set "
10572f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        + current.BSSID + " -> bail");
1058b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
1059e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
10604dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
10614dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1062931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Determine which BSSID we want to associate to, taking account
1063c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle        // relative strength of 5 and 2.4 GHz BSSIDs
10642451dbcc4f9641df188326215b204b798eb70c46vandwalle        long nowMs = System.currentTimeMillis();
10654dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
106625ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande        for (ScanDetail sd : scanDetailCache.values()) {
106725ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande            ScanResult b = sd.getScanResult();
106897b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int bRssiBoost5 = 0;
106997b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int aRssiBoost5 = 0;
107097b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int bRssiBoost = 0;
107197b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int aRssiBoost = 0;
107225ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande            if ((sd.getSeen() == 0) || (b.BSSID == null)
107325ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande                    || ((nowMs - sd.getSeen()) > age)
1074e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    || b.autoJoinStatus != ScanResult.ENABLED
1075e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    || b.numIpConfigFailures > 8) {
10764dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
10773a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
10784dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1079931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Pick first one
10804dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (a == null) {
10814dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                a = b;
10824dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
10834dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
10844dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1085e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            if (b.numIpConfigFailures < (a.numIpConfigFailures - 1)) {
1086e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                // Prefer a BSSID that doesn't have less number of Ip config failures
1087e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("attemptRoam: "
1088dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                        + b.BSSID + " rssi=" + b.level + " ipfail=" + b.numIpConfigFailures
1089e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " freq=" + b.frequency
1090e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " > "
1091dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                        + a.BSSID + " rssi=" + a.level + " ipfail=" + a.numIpConfigFailures
1092e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " freq=" + a.frequency);
1093e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                a = b;
1094e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                continue;
1095e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            }
1096e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle
10972451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Apply hysteresis: we favor the currentBSSID by giving it a boost
10987806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentBSSID != null && currentBSSID.equals(b.BSSID)) {
1099931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Reduce the benefit of hysteresis if RSSI <= -75
110077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                if (b.level <= mWifiConfigStore.bandPreferencePenaltyThreshold5.get()) {
11010eebae7334d6129f7ca1344e4b20199794994358vandwalle                    bRssiBoost = mWifiConfigStore.associatedHysteresisLow;
1102c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
11030eebae7334d6129f7ca1344e4b20199794994358vandwalle                    bRssiBoost = mWifiConfigStore.associatedHysteresisHigh;
1104c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
11054dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
11067806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentBSSID != null && currentBSSID.equals(a.BSSID)) {
110777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                if (a.level <= mWifiConfigStore.bandPreferencePenaltyThreshold5.get()) {
1108931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Reduce the benefit of hysteresis if RSSI <= -75
11090eebae7334d6129f7ca1344e4b20199794994358vandwalle                    aRssiBoost = mWifiConfigStore.associatedHysteresisLow;
1110c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
11110eebae7334d6129f7ca1344e4b20199794994358vandwalle                    aRssiBoost = mWifiConfigStore.associatedHysteresisHigh;
1112c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
11134dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
11142451dbcc4f9641df188326215b204b798eb70c46vandwalle
111597b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            // Favor 5GHz: give a boost to 5GHz BSSIDs, with a slightly progressive curve
11162451dbcc4f9641df188326215b204b798eb70c46vandwalle            //   Boost the BSSID if it is on 5GHz, above a threshold
11172451dbcc4f9641df188326215b204b798eb70c46vandwalle            //   But penalize it if it is on 5GHz and below threshold
111897b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //
111997b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   With he current threshold values, 5GHz network with RSSI above -55
112097b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   Are given a boost of 30DB which is enough to overcome the current BSSID
112197b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   hysteresis (+14) plus 2.4/5 GHz signal strength difference on most cases
11229f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            //
11239f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // The "current BSSID" Boost must be added to the BSSID's level so as to introduce\
11249f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // soem amount of hysteresis
1125e67ec726c07410073575473c0f50dc737629f5davandwalle            if (b.is5GHz()) {
11269f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                bRssiBoost5 = rssiBoostFrom5GHzRssi(b.level + bRssiBoost, b.BSSID);
11274dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
1128e67ec726c07410073575473c0f50dc737629f5davandwalle            if (a.is5GHz()) {
11299f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                aRssiBoost5 = rssiBoostFrom5GHzRssi(a.level + aRssiBoost, a.BSSID);
11304dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
11314dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1132dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            if (VDBG) {
1133c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                String comp = " < ";
1134dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                if (b.level + bRssiBoost + bRssiBoost5 > a.level + aRssiBoost + aRssiBoost5) {
1135c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    comp = " > ";
1136c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
11374dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                logDbg("attemptRoam: "
1138c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + b.BSSID + " rssi=" + b.level + " boost=" + Integer.toString(bRssiBoost)
113997b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                        + "/" + Integer.toString(bRssiBoost5) + " freq=" + b.frequency
114097b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                        + comp
1141c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + a.BSSID + " rssi=" + a.level + " boost=" + Integer.toString(aRssiBoost)
1142c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + "/" + Integer.toString(aRssiBoost5) + " freq=" + a.frequency);
1143c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            }
1144c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle
11452451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Compare the RSSIs after applying the hysteresis boost and the 5GHz
11462451dbcc4f9641df188326215b204b798eb70c46vandwalle            // boost if applicable
1147dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            if (b.level + bRssiBoost + bRssiBoost5 > a.level + aRssiBoost + aRssiBoost5) {
1148931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // b is the better BSSID
1149c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                a = b;
11504dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
11514dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
11523a2a3d226881cce8a4e511302231d843b0def303vandwalle        if (a != null) {
1153dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            if (VDBG) {
11547806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                StringBuilder sb = new StringBuilder();
1155e67ec726c07410073575473c0f50dc737629f5davandwalle                sb.append("attemptRoam: " + current.configKey() +
1156e67ec726c07410073575473c0f50dc737629f5davandwalle                        " Found " + a.BSSID + " rssi=" + a.level + " freq=" + a.frequency);
11577806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                if (currentBSSID != null) {
11587806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                    sb.append(" Current: " + currentBSSID);
11597806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                }
11607806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                sb.append("\n");
11617806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                logDbg(sb.toString());
11623a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
11634dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
11643a2a3d226881cce8a4e511302231d843b0def303vandwalle        return a;
11654dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    }
11664dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1167931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
11682451dbcc4f9641df188326215b204b798eb70c46vandwalle     * getNetworkScore()
1169dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * <p/>
11702451dbcc4f9641df188326215b204b798eb70c46vandwalle     * if scorer is present, get the network score of a WifiConfiguration
1171dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle     * <p/>
11722451dbcc4f9641df188326215b204b798eb70c46vandwalle     * Note: this should be merge with setVisibility
11732451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
11742451dbcc4f9641df188326215b204b798eb70c46vandwalle     * @param config
11752451dbcc4f9641df188326215b204b798eb70c46vandwalle     * @return score
11762451dbcc4f9641df188326215b204b798eb70c46vandwalle     */
117781c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson    int getConfigNetworkScore(WifiConfiguration config, int age, boolean isActive) {
11782451dbcc4f9641df188326215b204b798eb70c46vandwalle
11792451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (mNetworkScoreCache == null) {
1180e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (VDBG) {
1181b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("       getConfigNetworkScore for " + config.configKey()
1182e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + "  -> no scorer, hence no scores");
1183e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
11841db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            return WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
11851db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        }
118625ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande
118725ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande        if (mWifiConfigStore.getScanDetailCache(config) == null) {
1188e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (VDBG) {
1189b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("       getConfigNetworkScore for " + config.configKey()
1190e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " -> no scan cache");
1191e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
11921db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            return WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
11932451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
11942451dbcc4f9641df188326215b204b798eb70c46vandwalle
11952451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Get current date
11962451dbcc4f9641df188326215b204b798eb70c46vandwalle        long nowMs = System.currentTimeMillis();
11972451dbcc4f9641df188326215b204b798eb70c46vandwalle
11981db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        int startScore = -10000;
11991db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle
12002451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Run thru all cached scan results
120125ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande        for (ScanDetail sd : mWifiConfigStore.getScanDetailCache(config).values()) {
120225ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande            ScanResult result = sd.getScanResult();
120325ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande            if ((nowMs - sd.getSeen()) < age) {
120481c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                int sc = mNetworkScoreCache.getNetworkScore(result, isActive);
12051db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle                if (sc > startScore) {
12061db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle                    startScore = sc;
12072451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
12082451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
12092451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
12101db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        if (startScore == -10000) {
12111db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            startScore = WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
12121db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        }
1213e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle        if (VDBG) {
1214e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (startScore == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
1215b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    getConfigNetworkScore for " + config.configKey()
1216e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " -> no available score");
1217e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            } else {
1218b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    getConfigNetworkScore for " + config.configKey()
121981c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                        + " isActive=" + isActive
1220e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " score = " + Integer.toString(startScore));
1221e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
1222e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle        }
1223e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle
12241db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        return startScore;
12252451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
12262451dbcc4f9641df188326215b204b798eb70c46vandwalle
12272451dbcc4f9641df188326215b204b798eb70c46vandwalle    /**
12288639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson     * Set whether connections to untrusted connections are allowed.
12298639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson     */
12308639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    void setAllowUntrustedConnections(boolean allow) {
12318639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        boolean changed = mAllowUntrustedConnections != allow;
12328639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        mAllowUntrustedConnections = allow;
12338639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        if (changed) {
1234005c1ef113192f898499a407dd266393a8d6b076vandwalle            // Trigger a scan so as to reattempt autojoin
1235005c1ef113192f898499a407dd266393a8d6b076vandwalle            mWifiStateMachine.startScanForUntrustedSettingChange();
12368639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        }
12378639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    }
12388639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
12398639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    private boolean isOpenNetwork(ScanResult result) {
12408639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        return !result.capabilities.contains("WEP") &&
12418639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                !result.capabilities.contains("PSK") &&
12428639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                !result.capabilities.contains("EAP");
12438639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    }
12448639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
124516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson    private boolean haveRecentlySeenScoredBssid(WifiConfiguration config) {
124616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        long ephemeralOutOfRangeTimeoutMs = Settings.Global.getLong(
124716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                mContext.getContentResolver(),
124816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                Settings.Global.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS,
124916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                DEFAULT_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS);
125016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
125116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // Check whether the currently selected network has a score curve. If
125216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // ephemeralOutOfRangeTimeoutMs is <= 0, then this is all we check, and we stop here.
125316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // Otherwise, we stop here if the currently selected network has a score. If it doesn't, we
125416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // keep going - it could be that another BSSID is in range (has been seen recently) which
125516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // has a score, even if the one we're immediately connected to doesn't.
1256dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        ScanResult currentScanResult = mWifiStateMachine.getCurrentScanResult();
125716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        boolean currentNetworkHasScoreCurve = mNetworkScoreCache.hasScoreCurve(currentScanResult);
125816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        if (ephemeralOutOfRangeTimeoutMs <= 0 || currentNetworkHasScoreCurve) {
125916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            if (DBG) {
126016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                if (currentNetworkHasScoreCurve) {
126116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    logDbg("Current network has a score curve, keeping network: "
126216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                            + currentScanResult);
126316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                } else {
126416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    logDbg("Current network has no score curve, giving up: " + config.SSID);
126516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                }
126616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            }
126716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            return currentNetworkHasScoreCurve;
126816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        }
126916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
127025ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande        if (mWifiConfigStore.getScanDetailCache(config) == null
127125ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande                || mWifiConfigStore.getScanDetailCache(config).isEmpty()) {
127216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            return false;
127316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        }
127416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
127516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        long currentTimeMs = System.currentTimeMillis();
127625ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande        for (ScanDetail sd : mWifiConfigStore.getScanDetailCache(config).values()) {
127725ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande            ScanResult result = sd.getScanResult();
127825ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande            if (currentTimeMs > sd.getSeen()
127925ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande                    && currentTimeMs - sd.getSeen() < ephemeralOutOfRangeTimeoutMs
128016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    && mNetworkScoreCache.hasScoreCurve(result)) {
128116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                if (DBG) {
128216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    logDbg("Found scored BSSID, keeping network: " + result.BSSID);
128316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                }
128416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                return true;
128516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            }
128616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        }
128716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
128816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        if (DBG) {
128916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            logDbg("No recently scored BSSID found, giving up connection: " + config.SSID);
129016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        }
129116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        return false;
129216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson    }
129316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
129477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // After WifiStateMachine ask the supplicant to associate or reconnect
129577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // we might still obtain scan results from supplicant
129677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // however the supplicant state in the mWifiInfo and supplicant state tracker
129777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // are updated when we get the supplicant state change message which can be
129877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // processed after the SCAN_RESULT message, so at this point the framework doesn't
129977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // know that supplicant is ASSOCIATING.
130077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // A good fix for this race condition would be for the WifiStateMachine to add
130177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // a new transient state where it expects to get the supplicant message indicating
130277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // that it started the association process and within which critical operations
130377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // like autojoin should be deleted.
130477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
130577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // This transient state would remove the need for the roam Wathchdog which
130677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // basically does that.
130777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
130877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // At the moment, we just query the supplicant state synchronously with the
130977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // mWifiNative.status() command, which allow us to know that
131077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // supplicant has started association process, even though we didnt yet get the
131177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // SUPPLICANT_STATE_CHANGE message.
131277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
131377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final List<String> ASSOC_STATES = Arrays.asList(
131477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "ASSOCIATING",
131577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "ASSOCIATED",
131677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "FOUR_WAY_HANDSHAKE",
131777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "GROUP_KEY_HANDSHAKE");
131877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
131977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private int getNetID(String wpaStatus) {
132077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (VDBG) {
132177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            logDbg("attemptAutoJoin() status=" + wpaStatus);
132277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
132377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
132477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        try {
132577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            int id = WifiConfiguration.INVALID_NETWORK_ID;
132677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            String state = null;
132777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            BufferedReader br = new BufferedReader(new StringReader(wpaStatus));
132877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            String line;
1329dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            while ((line = br.readLine()) != null) {
133077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                int split = line.indexOf('=');
133177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                if (split < 0) {
133277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    continue;
133377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                }
133477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
133577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                String name = line.substring(0, split);
133677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                if (name.equals("id")) {
133777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    try {
1338dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                        id = Integer.parseInt(line.substring(split + 1));
133977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        if (state != null) {
134077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                            break;
134177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        }
1342dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    } catch (NumberFormatException nfe) {
134377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        return WifiConfiguration.INVALID_NETWORK_ID;
134477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    }
1345dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                } else if (name.equals("wpa_state")) {
1346dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    state = line.substring(split + 1);
134777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    if (ASSOC_STATES.contains(state)) {
134877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        return WifiConfiguration.INVALID_NETWORK_ID;
1349dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    } else if (id >= 0) {
135077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        break;
135177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    }
135277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                }
135377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
135477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return id;
1355dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        } catch (IOException ioe) {
135677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return WifiConfiguration.INVALID_NETWORK_ID;    // Won't happen
135777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
135877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
135977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
136077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private boolean setCurrentConfigurationKey(WifiConfiguration currentConfig,
136177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                                               int supplicantNetId) {
136277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (currentConfig != null) {
136377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (supplicantNetId != currentConfig.networkId
136477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    // https://b.corp.google.com/issue?id=16484607
136577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    // mark this condition as an error only if the mismatched networkId are valid
136677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    && supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID
136777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    && currentConfig.networkId != WifiConfiguration.INVALID_NETWORK_ID) {
136877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                logDbg("attemptAutoJoin() ERROR wpa_supplicant out of sync nid="
136977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        + Integer.toString(supplicantNetId) + " WifiStateMachine="
137077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        + Integer.toString(currentConfig.networkId));
137177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mWifiStateMachine.disconnectCommand();
137277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                return false;
137377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            } else if (currentConfig.ephemeral && (!mAllowUntrustedConnections ||
137477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    !haveRecentlySeenScoredBssid(currentConfig))) {
137577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // The current connection is untrusted (the framework added it), but we're either
137677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // no longer allowed to connect to such networks, the score has been nullified
137777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // since we connected, or the scored BSSID has gone out of range.
137877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // Drop the current connection and perform the rest of autojoin.
137977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                logDbg("attemptAutoJoin() disconnecting from unwanted ephemeral network");
138077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mWifiStateMachine.disconnectCommand(Process.WIFI_UID,
138177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        mAllowUntrustedConnections ? 1 : 0);
138277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                return false;
138377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            } else {
138477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mCurrentConfigurationKey = currentConfig.configKey();
138577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                return true;
138677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
138777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        } else {
138877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            // If not invalid, then maybe in the process of associating, skip this attempt
138977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return supplicantNetId == WifiConfiguration.INVALID_NETWORK_ID;
139077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
139177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
139277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
139377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private void updateBlackListStatus(WifiConfiguration config, long now) {
139477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        // Wait for 5 minutes before reenabling config that have known,
139577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        // repeated connection or DHCP failures
139677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (config.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE
139777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                || config.disableReason
139877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                == WifiConfiguration.DISABLED_ASSOCIATION_REJECT
139977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                || config.disableReason
140077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                == WifiConfiguration.DISABLED_AUTH_FAILURE) {
140177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (config.blackListTimestamp == 0
140277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    || (config.blackListTimestamp > now)) {
140377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // Sanitize the timestamp
140477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.blackListTimestamp = now;
140577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
140677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if ((now - config.blackListTimestamp) >
140777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    mWifiConfigStore.wifiConfigBlacklistMinTimeMilli) {
140877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // Re-enable the WifiConfiguration
140977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.status = WifiConfiguration.Status.ENABLED;
141077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
141177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // Reset the blacklist condition
141277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.numConnectionFailures = 0;
141377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.numIpConfigFailures = 0;
141477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.numAuthFailures = 0;
141577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
141677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
141777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.dirty = true;
141877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            } else {
141977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                if (VDBG) {
142077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    long delay = mWifiConfigStore.wifiConfigBlacklistMinTimeMilli
142177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                            - (now - config.blackListTimestamp);
142277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    logDbg("attemptautoJoin " + config.configKey()
142377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                            + " dont unblacklist yet, waiting for "
142477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                            + delay + " ms");
142577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                }
142677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
142777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
142877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        // Avoid networks disabled because of AUTH failure altogether
142977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (DBG) {
143077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            logDbg("attemptAutoJoin skip candidate due to auto join status "
143177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    + Integer.toString(config.autoJoinStatus) + " key "
143277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    + config.configKey(true)
143377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    + " reason " + config.disableReason);
143477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
143577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
1436dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle
143777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    boolean underSoftThreshold(WifiConfiguration config) {
143877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return config.visibility.rssi24 < mWifiConfigStore.thresholdUnblacklistThreshold24Soft.get()
1439dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                && config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Soft.get();
144077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
144177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
144277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    boolean underHardThreshold(WifiConfiguration config) {
144377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return config.visibility.rssi24 < mWifiConfigStore.thresholdUnblacklistThreshold24Hard.get()
1444dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                && config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Hard.get();
144577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
144677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
144777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    boolean underThreshold(WifiConfiguration config, int rssi24, int rssi5) {
144877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return config.visibility.rssi24 < rssi24 && config.visibility.rssi5 < rssi5;
144977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
145077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
14518639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    /**
1452931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * attemptAutoJoin() function implements the core of the a network switching algorithm
145368fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle     * Return false if no acceptable networks were found.
1454931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
145568fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle    boolean attemptAutoJoin() {
145668fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle        boolean found = false;
1457c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        didOverride = false;
14581ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        didBailDueToWeakRssi = false;
1459b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        int networkSwitchType = AUTO_JOIN_IDLE;
14604dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
14618242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle        long now = System.currentTimeMillis();
14628242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle
14638c9088d11880553458f09377cc60d6eb7e66747bvandwalle        String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
14648c9088d11880553458f09377cc60d6eb7e66747bvandwalle
1465931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Reset the currentConfiguration Key, and set it only if WifiStateMachine and
1466453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        // supplicant agree
1467453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        mCurrentConfigurationKey = null;
1468453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        WifiConfiguration currentConfiguration = mWifiStateMachine.getCurrentWifiConfiguration();
1469453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
1470f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration candidate = null;
1471f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1472931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Obtain the subset of recently seen networks
1473833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        List<WifiConfiguration> list =
1474833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                mWifiConfigStore.getRecentConfiguredNetworks(mScanResultAutoJoinAge, false);
1475f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (list == null) {
1476dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            if (VDBG) logDbg("attemptAutoJoin nothing known=" +
147731891afce40b903ada9b24ec12e3648ae6aa27b2Jan Nordqvist                    mWifiConfigStore.getConfiguredNetworksSize());
147868fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle            return false;
1479f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1480f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1481931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Find the currently connected network: ask the supplicant directly
148277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        int supplicantNetId = getNetID(mWifiNative.status(true));
148349bc8dd35845318cd9bc5ce9064fc1ad33bbece8xinhe
1484ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (DBG) {
14857806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            String conf = "";
1486b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String last = "";
14877806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentConfiguration != null) {
1488e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                conf = " current=" + currentConfiguration.configKey();
1489b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1490b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (lastSelectedConfiguration != null) {
14912f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                last = " last=" + lastSelectedConfiguration;
14927806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            }
1493ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            logDbg("attemptAutoJoin() num recent config " + Integer.toString(list.size())
1494b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + conf + last
1495b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + " ---> suppNetId=" + Integer.toString(supplicantNetId));
1496ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
1497f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
149877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (!setCurrentConfigurationKey(currentConfiguration, supplicantNetId)) {
149977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return false;
1500453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        }
1501453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
1502b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        int currentNetId = -1;
1503b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentConfiguration != null) {
1504931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // If we are associated to a configuration, it will
1505b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            // be compared thru the compareNetwork function
1506b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            currentNetId = currentConfiguration.networkId;
1507b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
1508b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle
1509931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1510931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * Run thru all visible configurations without looking at the one we
1511c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle         * are currently associated to
15124dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle         * select Best Network candidate from known WifiConfigurations
1513931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1514f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (WifiConfiguration config : list) {
1515e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            if (config.SSID == null) {
1516b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                continue;
1517e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            }
1518e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
151977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (config.autoJoinStatus >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
152077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                updateBlackListStatus(config, now);
1521f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1522f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1523f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1524e487a4648dd41881e754f1224aaedead78a0777dSky Faber            if (config.userApproved == WifiConfiguration.USER_PENDING ||
1525e487a4648dd41881e754f1224aaedead78a0777dSky Faber                    config.userApproved == WifiConfiguration.USER_BANNED) {
1526e487a4648dd41881e754f1224aaedead78a0777dSky Faber                if (DBG) {
1527e487a4648dd41881e754f1224aaedead78a0777dSky Faber                    logDbg("attemptAutoJoin skip candidate due to user approval status "
1528e487a4648dd41881e754f1224aaedead78a0777dSky Faber                            + WifiConfiguration.userApprovedAsString(config.userApproved) + " key "
1529e487a4648dd41881e754f1224aaedead78a0777dSky Faber                            + config.configKey(true));
1530e487a4648dd41881e754f1224aaedead78a0777dSky Faber                }
1531e487a4648dd41881e754f1224aaedead78a0777dSky Faber                continue;
1532e487a4648dd41881e754f1224aaedead78a0777dSky Faber            }
1533e487a4648dd41881e754f1224aaedead78a0777dSky Faber
1534931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to un-blacklist based on elapsed time
153527355a942653264388e909a4276196ee63e57811vandwalle            if (config.blackListTimestamp > 0) {
153627355a942653264388e909a4276196ee63e57811vandwalle                if (now < config.blackListTimestamp) {
1537931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    /**
1538931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * looks like there was a change in the system clock since we black listed, and
1539931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * timestamp is not meaningful anymore, hence lose it.
1540931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * this event should be rare enough so that we still want to lose the black list
15412451dbcc4f9641df188326215b204b798eb70c46vandwalle                     */
154227355a942653264388e909a4276196ee63e57811vandwalle                    config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
154327355a942653264388e909a4276196ee63e57811vandwalle                } else {
15444dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    if ((now - config.blackListTimestamp) > loseBlackListHardMilli) {
1545931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Reenable it after 18 hours, i.e. next day
154627355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
15474dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    } else if ((now - config.blackListTimestamp) > loseBlackListSoftMilli) {
1548931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Lose blacklisting due to bad link
154927355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(config.autoJoinStatus - 8);
155027355a942653264388e909a4276196ee63e57811vandwalle                    }
155127355a942653264388e909a4276196ee63e57811vandwalle                }
155227355a942653264388e909a4276196ee63e57811vandwalle            }
155327355a942653264388e909a4276196ee63e57811vandwalle
155477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (config.visibility == null) {
155577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                continue;
155677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
155777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1558931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to unblacklist based on good visibility
155977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (underSoftThreshold(config)) {
156021d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                if (DBG) {
156121d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                    logDbg("attemptAutoJoin do not unblacklist due to low visibility " +
156221d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                            config.configKey() + " status=" + config.autoJoinStatus);
156321d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                }
156477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            } else if (underHardThreshold(config)) {
1565931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // If the network is simply temporary disabled, don't allow reconnect until
1566931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // RSSI becomes good enough
156727355a942653264388e909a4276196ee63e57811vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 1);
156821d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                if (DBG) {
156921d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped soft -> status=" +
157021d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                            config.configKey() + " status=" + config.autoJoinStatus);
157121d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                }
157227355a942653264388e909a4276196ee63e57811vandwalle            } else {
1573c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 3);
157421d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                if (DBG) {
157521d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped hard -> status=" +
157621d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                            config.configKey() + " status=" + config.autoJoinStatus);
157721d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                }
157827355a942653264388e909a4276196ee63e57811vandwalle            }
157927355a942653264388e909a4276196ee63e57811vandwalle
158027355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
158127355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED) {
1582931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Network is blacklisted, skip
158321d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                if (DBG) {
158421d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                    logDbg("attemptAutoJoin skip blacklisted -> status=" +
158521d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                            config.configKey() + " status=" + config.autoJoinStatus);
158621d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                }
158727355a942653264388e909a4276196ee63e57811vandwalle                continue;
158827355a942653264388e909a4276196ee63e57811vandwalle            }
1589f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (config.networkId == currentNetId) {
1590ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
159121bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    logDbg("attemptAutoJoin skip current candidate  "
159221bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                            + Integer.toString(currentNetId)
1593ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + " key " + config.configKey(true));
1594ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
1595f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1596f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1597f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
15980eebae7334d6129f7ca1344e4b20199794994358vandwalle            boolean isLastSelected = false;
15990eebae7334d6129f7ca1344e4b20199794994358vandwalle            if (lastSelectedConfiguration != null &&
16000eebae7334d6129f7ca1344e4b20199794994358vandwalle                    config.configKey().equals(lastSelectedConfiguration)) {
16010eebae7334d6129f7ca1344e4b20199794994358vandwalle                isLastSelected = true;
16020eebae7334d6129f7ca1344e4b20199794994358vandwalle            }
16030eebae7334d6129f7ca1344e4b20199794994358vandwalle
16044fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle            if (config.lastRoamingFailure != 0
16054fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                    && currentConfiguration != null
16064fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                    && (lastSelectedConfiguration == null
16074fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                    || !config.configKey().equals(lastSelectedConfiguration))) {
16084fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                // Apply blacklisting for roaming to this config if:
16094fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                //   - the target config had a recent roaming failure
16104fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                //   - we are currently associated
16114fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                //   - the target config is not the last selected
16124fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                if (now > config.lastRoamingFailure
16134fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                        && (now - config.lastRoamingFailure)
16144fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                        < config.roamingFailureBlackListTimeMilli) {
16154fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                    if (DBG) {
16164fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                        logDbg("compareNetwork not switching to " + config.configKey()
16174fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                                + " from current " + currentConfiguration.configKey()
16184fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                                + " because it is blacklisted due to roam failure, "
16194fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                                + " blacklist remain time = "
16204fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                                + (now - config.lastRoamingFailure) + " ms");
16214fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                    }
16224fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                    continue;
16234fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                }
16244fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle            }
16254fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle
16261ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            int boost = config.autoJoinUseAggressiveJoinAttemptThreshold + weakRssiBailCount;
162777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (underThreshold(config,
162877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    mWifiConfigStore.thresholdInitialAutoJoinAttemptMin24RSSI.get() - boost,
162977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    mWifiConfigStore.thresholdInitialAutoJoinAttemptMin5RSSI.get() - boost)) {
163077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
163121d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                if (DBG) {
163221d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                    logDbg("attemptAutoJoin skip due to low visibility " + config.configKey());
163321d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                }
16340eebae7334d6129f7ca1344e4b20199794994358vandwalle
1635c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // Don't try to autojoin a network that is too far but
1636c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // If that configuration is a user's choice however, try anyway
16370eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (!isLastSelected) {
16380eebae7334d6129f7ca1344e4b20199794994358vandwalle                    config.autoJoinBailedDueToLowRssi = true;
16391ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                    didBailDueToWeakRssi = true;
16408c9088d11880553458f09377cc60d6eb7e66747bvandwalle                    continue;
16410eebae7334d6129f7ca1344e4b20199794994358vandwalle                } else {
16420eebae7334d6129f7ca1344e4b20199794994358vandwalle                    // Next time, try to be a bit more aggressive in auto-joining
16430eebae7334d6129f7ca1344e4b20199794994358vandwalle                    if (config.autoJoinUseAggressiveJoinAttemptThreshold
1644dd0c558776fcfba3f754bb0cd6533f2c9c23ec1evandwalle                            < WifiConfiguration.MAX_INITIAL_AUTO_JOIN_RSSI_BOOST
1645dd0c558776fcfba3f754bb0cd6533f2c9c23ec1evandwalle                            && config.autoJoinBailedDueToLowRssi) {
1646dd0c558776fcfba3f754bb0cd6533f2c9c23ec1evandwalle                        config.autoJoinUseAggressiveJoinAttemptThreshold += 4;
16474dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    }
16488c9088d11880553458f09377cc60d6eb7e66747bvandwalle                }
16490eebae7334d6129f7ca1344e4b20199794994358vandwalle            }
1650d30127db46224e45554f8964209221bba8ad41d9vandwalle            if (config.numNoInternetAccessReports > 0
1651d30127db46224e45554f8964209221bba8ad41d9vandwalle                    && !isLastSelected
1652d30127db46224e45554f8964209221bba8ad41d9vandwalle                    && !config.validatedInternetAccess) {
1653d30127db46224e45554f8964209221bba8ad41d9vandwalle                // Avoid autoJoining this network because last time we used it, it didn't
1654d30127db46224e45554f8964209221bba8ad41d9vandwalle                // have internet access, and we never manage to validate internet access on this
1655d30127db46224e45554f8964209221bba8ad41d9vandwalle                // network configuration
16560eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (DBG) {
1657d30127db46224e45554f8964209221bba8ad41d9vandwalle                    logDbg("attemptAutoJoin skip candidate due to no InternetAccess  "
1658d30127db46224e45554f8964209221bba8ad41d9vandwalle                            + config.configKey(true)
1659d30127db46224e45554f8964209221bba8ad41d9vandwalle                            + " num reports " + config.numNoInternetAccessReports);
16609f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                }
16610eebae7334d6129f7ca1344e4b20199794994358vandwalle                continue;
16628c9088d11880553458f09377cc60d6eb7e66747bvandwalle            }
16638c9088d11880553458f09377cc60d6eb7e66747bvandwalle
1664ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            if (DBG) {
1665e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                String cur = "";
1666e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                if (candidate != null) {
1667e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    cur = " current candidate " + candidate.configKey();
1668e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                }
1669e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("attemptAutoJoin trying id="
1670c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + Integer.toString(config.networkId) + " "
1671b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                        + config.configKey(true)
1672e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " status=" + config.autoJoinStatus
1673e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + cur);
1674ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            }
1675f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1676f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate == null) {
1677f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                candidate = config;
1678f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
1679dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                if (VDBG) {
1680453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("attemptAutoJoin will compare candidate  " + candidate.configKey()
16814dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " with " + config.configKey());
1682f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
16834d381bc39f5263effdae73ec99065eb299b806caVinit Deshpande
1684833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                int order = compareWifiConfigurations(candidate, config);
16854d381bc39f5263effdae73ec99065eb299b806caVinit Deshpande                if (VDBG) {
16864d381bc39f5263effdae73ec99065eb299b806caVinit Deshpande                    logDbg("attemptAutoJoin compareWifiConfigurations returned " + order);
16874d381bc39f5263effdae73ec99065eb299b806caVinit Deshpande                }
16882451dbcc4f9641df188326215b204b798eb70c46vandwalle
16892451dbcc4f9641df188326215b204b798eb70c46vandwalle                // The lastSelectedConfiguration is the configuration the user has manually selected
1690c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // thru WifiPicker, or that a 3rd party app asked us to connect to via the
16912451dbcc4f9641df188326215b204b798eb70c46vandwalle                // enableNetwork with disableOthers=true WifiManager API
16922451dbcc4f9641df188326215b204b798eb70c46vandwalle                // As this is a direct user choice, we strongly prefer this configuration,
16932451dbcc4f9641df188326215b204b798eb70c46vandwalle                // hence give +/-100
16942451dbcc4f9641df188326215b204b798eb70c46vandwalle                if ((lastSelectedConfiguration != null)
16952451dbcc4f9641df188326215b204b798eb70c46vandwalle                        && candidate.configKey().equals(lastSelectedConfiguration)) {
16962451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // candidate is the last selected configuration,
16972451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // so keep it above connect choices (+/-60) and
16982451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // above RSSI/scorer based selection of linked configuration (+/- 50)
16992451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // by reducing order by -100
17002451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = order - 100;
1701dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    if (VDBG) {
17022f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        logDbg("     ...and prefers -100 " + candidate.configKey()
17032451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " over " + config.configKey()
17042451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " because it is the last selected -> "
17052451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + Integer.toString(order));
17062451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
17072451dbcc4f9641df188326215b204b798eb70c46vandwalle                } else if ((lastSelectedConfiguration != null)
17082451dbcc4f9641df188326215b204b798eb70c46vandwalle                        && config.configKey().equals(lastSelectedConfiguration)) {
17092451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // config is the last selected configuration,
17102451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // so keep it above connect choices (+/-60) and
17112451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // above RSSI/scorer based selection of linked configuration (+/- 50)
17122451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // by increasing order by +100
17132451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = order + 100;
1714dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    if (VDBG) {
17152f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        logDbg("     ...and prefers +100 " + config.configKey()
17162451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " over " + candidate.configKey()
17172451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " because it is the last selected -> "
17182451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + Integer.toString(order));
17192451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
17202451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
17212451dbcc4f9641df188326215b204b798eb70c46vandwalle
1722f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (order > 0) {
1723931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Ascending : candidate < config
1724f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    candidate = config;
1725f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1726f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1727f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1728f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
17292451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Now, go thru scan result to try finding a better untrusted network
1730833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        if (mNetworkScoreCache != null && mAllowUntrustedConnections) {
1731f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi5 = WifiConfiguration.INVALID_RSSI;
1732f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi24 = WifiConfiguration.INVALID_RSSI;
1733f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate != null) {
1734f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi5 = candidate.visibility.rssi5;
1735f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi24 = candidate.visibility.rssi24;
1736f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1737f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1738931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Get current date
17392451dbcc4f9641df188326215b204b798eb70c46vandwalle            long nowMs = System.currentTimeMillis();
1740c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            int currentScore = -10000;
1741c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // The untrusted network with highest score
174225ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande            ScanDetail untrustedCandidate = null;
17432451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Look for untrusted scored network only if the current candidate is bad
1744c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (isBadCandidate(rssi24, rssi5)) {
174525ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande                for (ScanDetail scanDetail : scanResultCache.values()) {
174625ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande                    ScanResult result = scanDetail.getScanResult();
1747c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // We look only at untrusted networks with a valid SSID
1748c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // A trusted result would have been looked at thru it's Wificonfiguration
17498639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                    if (TextUtils.isEmpty(result.SSID) || !result.untrusted ||
17508639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                            !isOpenNetwork(result)) {
1751c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        continue;
1752c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    }
17532c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                    String quotedSSID = "\"" + result.SSID + "\"";
17542c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                    if (mWifiConfigStore.mDeletedEphemeralSSIDs.contains(quotedSSID)) {
17552ce99b40c36ed0352b31aa85d5f9383d5f0506f5vandwalle                        // SSID had been Forgotten by user, then don't score it
17562ce99b40c36ed0352b31aa85d5f9383d5f0506f5vandwalle                        continue;
17572ce99b40c36ed0352b31aa85d5f9383d5f0506f5vandwalle                    }
1758833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                    if ((nowMs - result.seen) < mScanResultAutoJoinAge) {
1759c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        // Increment usage count for the network
17602c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                        mWifiConnectionStatistics.incrementOrAddUntrusted(quotedSSID, 0, 1);
1761c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
17622c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                        boolean isActiveNetwork = currentConfiguration != null
17632c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                                && currentConfiguration.SSID.equals(quotedSSID);
176481c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                        int score = mNetworkScoreCache.getNetworkScore(result, isActiveNetwork);
1765c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        if (score != WifiNetworkScoreCache.INVALID_NETWORK_SCORE
1766c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                && score > currentScore) {
1767c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            // Highest score: Select this candidate
1768c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            currentScore = score;
176925ee2d5d30434712b28aef6eec9460035101e493Vinit Deshpande                            untrustedCandidate = scanDetail;
1770c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            if (VDBG) {
1771c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                logDbg("AutoJoinController: found untrusted candidate "
1772c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                        + result.SSID
1773dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                                        + " RSSI=" + result.level
1774dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                                        + " freq=" + result.frequency
1775dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                                        + " score=" + score);
1776c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            }
1777f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        }
1778f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
1779f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1780f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1781c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (untrustedCandidate != null) {
17828639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                // At this point, we have an untrusted network candidate.
17838639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                // Create the new ephemeral configuration and see if we should switch over
1784833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                candidate =
1785833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                        mWifiConfigStore.wifiConfigurationFromScanResult(untrustedCandidate);
1786833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                candidate.allowedKeyManagement.set(KeyMgmt.NONE);
1787833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                candidate.ephemeral = true;
1788fb650bfb264b7ff31c927498faf8343b5895c6abPierre Vandwalle                candidate.dirty = true;
1789c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            }
1790c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        }
1791b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
17921ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        long lastUnwanted =
17931ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                System.currentTimeMillis()
17941ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                        - mWifiConfigStore.lastUnwantedNetworkDisconnectTimestamp;
17951ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        if (candidate == null
17961ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && lastSelectedConfiguration == null
17971ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && currentConfiguration == null
17981ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && didBailDueToWeakRssi
17991ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && (mWifiConfigStore.lastUnwantedNetworkDisconnectTimestamp == 0
1800dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                || lastUnwanted > (1000 * 60 * 60 * 24 * 7))
18011ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                ) {
18021ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // We are bailing out of autojoin although we are seeing a weak configuration, and
18031ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - we didn't find another valid candidate
18041ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - we are not connected
18051ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - without a user network selection choice
18061ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - ConnectivityService has not triggered an unwanted network disconnect
18071ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            //       on this device for a week (hence most likely there is no SIM card or cellular)
18081ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // If all those conditions are met, then boost the RSSI of the weak networks
18091ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // that we are seeing so as we will eventually pick one
18101ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            if (weakRssiBailCount < 10)
18111ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                weakRssiBailCount += 1;
18121ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        } else {
18131ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            if (weakRssiBailCount > 0)
18141ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                weakRssiBailCount -= 1;
18151ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        }
18161ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle
1817931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1818931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         *  If candidate is found, check the state of the connection so as
1819931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         *  to decide if we should be acting on this candidate and switching over
1820931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1821e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        int networkDelta = compareNetwork(candidate, lastSelectedConfiguration);
1822b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (DBG && candidate != null) {
1823b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String doSwitch = "";
1824b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String current = "";
1825b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (networkDelta < 0) {
1826b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                doSwitch = " -> not switching";
1827b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1828b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (currentConfiguration != null) {
18292f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                current = " with current " + currentConfiguration.configKey();
1830b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1831b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("attemptAutoJoin networkSwitching candidate "
1832b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                    + candidate.configKey()
1833b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + current
1834c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    + " linked=" + (currentConfiguration != null
1835dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    && currentConfiguration.isLinked(candidate))
1836b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + " : delta="
1837b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + Integer.toString(networkDelta) + " "
1838b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + doSwitch);
1839b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
18404dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1841931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1842931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * Ask WifiStateMachine permission to switch :
1843931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * if user is currently streaming voice traffic,
1844931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * then we should not be allowed to switch regardless of the delta
1845931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
184677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (mWifiStateMachine.shouldSwitchNetwork(networkDelta)) {      // !!! JNo: Here!
1847b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (mStaStaSupported) {
1848b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("mStaStaSupported --> error do nothing now ");
1849b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            } else {
1850b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (currentConfiguration != null && currentConfiguration.isLinked(candidate)) {
1851b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_EXTENDED_ROAMING;
1852b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                } else {
1853b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_OUT_OF_NETWORK_ROAMING;
1854b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1855b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1856b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto connect with netId "
1857b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(candidate.networkId)
1858b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " to " + candidate.configKey());
1859b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
18602451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (didOverride) {
18612451dbcc4f9641df188326215b204b798eb70c46vandwalle                    candidate.numScorerOverrideAndSwitchedNetwork++;
18622451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
1863c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                candidate.numAssociation++;
1864e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                mWifiConnectionStatistics.numAutoJoinAttempt++;
18659f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
18662c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                if (candidate.ephemeral) {
18672c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                    // We found a new candidate that we are going to connect to, then
18682c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                    // increase its connection count
18692c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                    mWifiConnectionStatistics.
18702c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                            incrementOrAddUntrusted(candidate.SSID, 1, 0);
18712c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                }
18722c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson
18732f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                if (candidate.BSSID == null || candidate.BSSID.equals("any")) {
18742f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // First step we selected the configuration we want to connect to
18752f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // Second step: Look for the best Scan result for this configuration
18762f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // TODO this algorithm should really be done in one step
18772f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    String currentBSSID = mWifiStateMachine.getCurrentBSSID();
1878833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                    ScanResult roamCandidate =
1879833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                            attemptRoam(null, candidate, mScanResultAutoJoinAge, null);
18802f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    if (roamCandidate != null && currentBSSID != null
18812f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                            && currentBSSID.equals(roamCandidate.BSSID)) {
18822f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // Sanity, we were already asociated to that candidate
18832f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        roamCandidate = null;
18842f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    }
18852f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    if (roamCandidate != null && roamCandidate.is5GHz()) {
18862f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // If the configuration hasn't a default BSSID selected, and the best
18872f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // candidate is 5GHZ, then select this candidate so as WifiStateMachine and
18882f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // supplicant will pick it first
18892f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        candidate.autoJoinBSSID = roamCandidate.BSSID;
18902f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        if (VDBG) {
18912f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                            logDbg("AutoJoinController: lock to 5GHz "
18922f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                                    + candidate.autoJoinBSSID
18932f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                                    + " RSSI=" + roamCandidate.level
18942f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                                    + " freq=" + roamCandidate.frequency);
18952f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        }
1896448c9536a302c58a79e271b1721c08b8882f800evandwalle                    } else {
1897448c9536a302c58a79e271b1721c08b8882f800evandwalle                        // We couldnt find a roam candidate
1898448c9536a302c58a79e271b1721c08b8882f800evandwalle                        candidate.autoJoinBSSID = "any";
18999f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    }
19009f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                }
1901448c9536a302c58a79e271b1721c08b8882f800evandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT,
1902dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                        candidate.networkId, networkSwitchType, candidate);
190368fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                found = true;
19044dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
1905b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
19064dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1907d4c25fd76644d5490700ae69fada4669de5193a1Pierre Vandwalle        if (networkSwitchType == AUTO_JOIN_IDLE && !mWifiConfigStore.enableHalBasedPno.get()) {
1908e67ec726c07410073575473c0f50dc737629f5davandwalle            String currentBSSID = mWifiStateMachine.getCurrentBSSID();
1909931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Attempt same WifiConfiguration roaming
1910833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle            ScanResult roamCandidate =
1911833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                    attemptRoam(null, currentConfiguration, mScanResultAutoJoinAge, currentBSSID);
1912e67ec726c07410073575473c0f50dc737629f5davandwalle            if (roamCandidate != null && currentBSSID != null
1913e67ec726c07410073575473c0f50dc737629f5davandwalle                    && currentBSSID.equals(roamCandidate.BSSID)) {
1914e67ec726c07410073575473c0f50dc737629f5davandwalle                roamCandidate = null;
1915e67ec726c07410073575473c0f50dc737629f5davandwalle            }
19162f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            if (roamCandidate != null && mWifiStateMachine.shouldSwitchNetwork(999)) {
1917b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1918b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto roam with netId "
1919b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(currentConfiguration.networkId)
1920b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " " + currentConfiguration.configKey() + " to BSSID="
1921b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + roamCandidate.BSSID + " freq=" + roamCandidate.frequency
19221ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                            + " RSSI=" + roamCandidate.level);
1923b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1924b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                networkSwitchType = AUTO_JOIN_ROAMING;
1925e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                mWifiConnectionStatistics.numAutoRoamAttempt++;
1926e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle
1927b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_ROAM,
1928dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                        currentConfiguration.networkId, 1, roamCandidate);
192968fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                found = true;
1930f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1931f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1932b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (VDBG) logDbg("Done attemptAutoJoin status=" + Integer.toString(networkSwitchType));
193368fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle        return found;
1934f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
193577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
193677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private void logDenial(String reason, WifiConfiguration config) {
193777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (!DBG) {
193877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return;
193977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
194077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        logDbg(reason + config.toString());
194177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
1942dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle
1943dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle    WifiConfiguration getWifiConfiguration(WifiNative.WifiPnoNetwork network) {
1944dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        if (network.configKey != null) {
1945dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            return mWifiConfigStore.getWifiConfiguration(network.configKey);
1946dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        }
1947dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        return null;
1948dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle    }
1949dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle
1950dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle    ArrayList<WifiNative.WifiPnoNetwork> getPnoList(WifiConfiguration current) {
1951dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        int size = -1;
19529ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle        ArrayList<WifiNative.WifiPnoNetwork> list = new ArrayList<WifiNative.WifiPnoNetwork>();
1953dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle
1954b0b0cc202b7d7aaad7b3f69d73e9b58ea2968b05Pierre Vandwalle        if (mWifiConfigStore.mCachedPnoList != null) {
1955b0b0cc202b7d7aaad7b3f69d73e9b58ea2968b05Pierre Vandwalle            size = mWifiConfigStore.mCachedPnoList.size();
1956dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        }
1957dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle
195821d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle        if (DBG) {
195921d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle            String s = "";
196021d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle            if (current != null) {
196121d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                s = " for: " + current.configKey();
196221d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle            }
196321d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle            Log.e(TAG, " get Pno List total size:" + size + s);
196421d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle        }
1965dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        if (current != null) {
1966dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            String configKey = current.configKey();
1967dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            /**
1968dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle             * If we are currently associated to a WifiConfiguration then include
1969dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle             * only those networks that have a higher priority
1970dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle             */
1971b0b0cc202b7d7aaad7b3f69d73e9b58ea2968b05Pierre Vandwalle            for (WifiNative.WifiPnoNetwork network : mWifiConfigStore.mCachedPnoList) {
1972dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                WifiConfiguration config = getWifiConfiguration(network);
19739ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                if (config == null) {
19749ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                    continue;
19759ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                }
19769ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                if (config.autoJoinStatus
19779ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                        >= WifiConfiguration.AUTO_JOIN_DISABLED_NO_CREDENTIALS) {
19789ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                     continue;
19799ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                }
19809ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle
19819ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                if (!configKey.equals(network.configKey)) {
198221d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                    int choice = getConnectChoice(config, current, true);
1983b0b0cc202b7d7aaad7b3f69d73e9b58ea2968b05Pierre Vandwalle                    if (choice > 0) {
1984b0b0cc202b7d7aaad7b3f69d73e9b58ea2968b05Pierre Vandwalle                        // config is of higher priority
198521d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                        if (DBG) {
198621d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                            Log.e(TAG, " Pno List adding:" + network.configKey
198721d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                                    + " choice " + choice);
198821d43c487ca1f719cd2c170e1fac88c7b62a836aPierre Vandwalle                        }
1989dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                        list.add(network);
1990b0b0cc202b7d7aaad7b3f69d73e9b58ea2968b05Pierre Vandwalle                        network.rssi_threshold = mWifiConfigStore.thresholdGoodRssi24.get();
1991dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                    }
1992dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle                }
1993dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle            }
1994dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        } else {
19959ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle            for (WifiNative.WifiPnoNetwork network : mWifiConfigStore.mCachedPnoList) {
19969ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                WifiConfiguration config = getWifiConfiguration(network);
19979ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                if (config == null) {
19989ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                    continue;
19999ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                }
20009ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                if (config.autoJoinStatus
20019ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                        >= WifiConfiguration.AUTO_JOIN_DISABLED_NO_CREDENTIALS) {
20029ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                    continue;
20039ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                }
20049ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                list.add(network);
20059ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle                network.rssi_threshold = mWifiConfigStore.thresholdGoodRssi24.get();
20069ccffbb6c3fe8eaa7d70cc3076d0dc3c6a9073e7Pierre Vandwalle            }
2007dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        }
2008dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle        return list;
2009dd490cf1df37b70a8625dc4ec8e712f740dd1e4aPierre Vandwalle    }
2010f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle}
2011f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
2012