WifiAutoJoinController.java revision ef1567e413c9ed5f5c4fdb9e354861632f7b2f87
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;
48ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport java.util.Collection;
49f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.HashMap;
5077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.util.Iterator;
51f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.List;
52ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistimport java.util.Map;
53f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
54f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle/**
55f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * AutoJoin controller is responsible for WiFi Connect decision
56f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
57f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * It runs in the thread context of WifiStateMachine
58f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
59f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle */
60f22d23092ab37286a5ef9d257d5bb32c421d2669vandwallepublic class WifiAutoJoinController {
61f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
62f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private Context mContext;
63f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiStateMachine mWifiStateMachine;
64f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiConfigStore mWifiConfigStore;
65f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNative mWifiNative;
66f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
67f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private NetworkScoreManager scoreManager;
68f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNetworkScoreCache mNetworkScoreCache;
69f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
70f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final String TAG = "WifiAutoJoinController ";
71ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean DBG = false;
72ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean VDBG = false;
73f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final boolean mStaStaSupported = false;
74f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
75c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    public static int mScanResultMaximumAge = 40000; /* milliseconds unit */
76833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle    public static int mScanResultAutoJoinAge = 5000; /* milliseconds unit */
77c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
78453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle    private String mCurrentConfigurationKey = null; //used by autojoin
79f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
8077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final HashMap<String, ScanResult> scanResultCache = new HashMap<>();
81f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
82c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    private WifiConnectionStatistics mWifiConnectionStatistics;
83c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
848639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    /** Whether to allow connections to untrusted networks. */
858639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    private boolean mAllowUntrustedConnections = false;
868639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
87c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    /* for debug purpose only : the untrusted SSID we would be connected to if we had VPN */
88c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    String lastUntrustedBSSID = null;
89c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
90c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    /* For debug purpose only: if the scored override a score */
91c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    boolean didOverride = false;
92c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
93931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Lose the non-auth failure blacklisting after 8 hours
944dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListHardMilli = 1000 * 60 * 60 * 8;
95931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Lose some temporary blacklisting after 30 minutes
964dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListSoftMilli = 1000 * 60 * 30;
9727355a942653264388e909a4276196ee63e57811vandwalle
9816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson    /** @see android.provider.Settings.Global#WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS */
9916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson    private static final long DEFAULT_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS = 1000 * 60; // 1 minute
10016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
101b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_IDLE = 0;
102b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_ROAMING = 1;
103b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_EXTENDED_ROAMING = 2;
104b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_OUT_OF_NETWORK_ROAMING = 3;
105b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
10697b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle    public static final int HIGH_THRESHOLD_MODIFIER = 5;
10797b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle
1081ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    // Below are AutoJoin wide parameters indicating if we should be aggressive before joining
1091ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    // weak network. Note that we cannot join weak network that are going to be marked as unanted by
1101ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    // ConnectivityService because this will trigger link flapping.
1111ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    /**
1121ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     * There was a non-blacklisted configuration that we bailed from because of a weak signal
1131ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     */
1141ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    boolean didBailDueToWeakRssi = false;
1151ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    /**
1161ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     * number of time we consecutively bailed out of an eligible network because its signal
1171ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     * was too weak
1181ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     */
1191ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    int weakRssiBailCount = 0;
1201ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle
121ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    private final AnqpCache mAnqpCache;
122ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    private final SupplicantBridge mSupplicantBridge;
123ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    private final List<PasspointMatchInfo> mMatchInfoList;
124ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
125f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    WifiAutoJoinController(Context c, WifiStateMachine w, WifiConfigStore s,
126c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                           WifiConnectionStatistics st, WifiNative n) {
127f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mContext = c;
128f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiStateMachine = w;
129f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore = s;
130f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiNative = n;
131f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mNetworkScoreCache = null;
132c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        mWifiConnectionStatistics = st;
13321bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle        scoreManager =
13421bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                (NetworkScoreManager) mContext.getSystemService(Context.NETWORK_SCORE_SERVICE);
135f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager == null)
136f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("Registered scoreManager NULL " + " service " + Context.NETWORK_SCORE_SERVICE);
137f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
138f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager != null) {
139f13817203179f41620514718c8668ae7e418f8afJeff Davidson            mNetworkScoreCache = new WifiNetworkScoreCache(mContext);
140f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            scoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
141f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        } else {
142f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("No network score service: Couldnt register as a WiFi score Manager, type="
143f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(NetworkKey.TYPE_WIFI)
144f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + " service " + Context.NETWORK_SCORE_SERVICE);
145f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            mNetworkScoreCache = null;
146f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
147ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
148ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        mMatchInfoList = new ArrayList<>();
149ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        Chronograph chronograph = new Chronograph();
150ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        mAnqpCache = new AnqpCache(chronograph);
151ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        mSupplicantBridge = new SupplicantBridge(mWifiNative, this);
152f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
153f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
154ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    void enableVerboseLogging(int verbose) {
155ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (verbose > 0 ) {
156abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = true;
157ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = true;
158ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        } else {
159abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = false;
160ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = false;
161ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
162ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    }
163ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle
164931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
165931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * Flush out scan results older than mScanResultMaximumAge
166ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     *
167931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
168f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private void ageScanResultsOut(int delay) {
169f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (delay <= 0) {
170931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            delay = mScanResultMaximumAge; // Something sane
171f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
172b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        long milli = System.currentTimeMillis();
173f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
174f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("ageScanResultsOut delay " + Integer.valueOf(delay) + " size "
175f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.valueOf(scanResultCache.size()) + " now " + Long.valueOf(milli));
176f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
177f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
178f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        Iterator<HashMap.Entry<String,ScanResult>> iter = scanResultCache.entrySet().iterator();
179f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        while (iter.hasNext()) {
180f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            HashMap.Entry<String,ScanResult> entry = iter.next();
181f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult result = entry.getValue();
182f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
183f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((result.seen + delay) < milli) {
184f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                iter.remove();
185f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
186f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
187f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
188f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
189ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    // !!! JNo >>
190ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
191ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    // !!! Call from addToScanCache
192ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    private ScanDetail scoreHSNetwork(ScanDetail scanDetail) {
193ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        NetworkDetail networkDetail = scanDetail.getNetworkDetail();
194ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        if (!networkDetail.has80211uInfo()) {
195ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            return null;
196ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        }
197ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        updateCache(scanDetail, networkDetail.getANQPElements());
198ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
199ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        Map<HomeSP, PasspointMatch> matches = matchNetwork(scanDetail,
200ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist                networkDetail.getANQPElements() == null);
201ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        if (!matches.isEmpty()) {
202ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            return scanDetail.score(matches);
203ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        } else {
204ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            return null;
205ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        }
206ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    }
207ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
208ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    private Map<HomeSP, PasspointMatch> matchNetwork(ScanDetail scanDetail, boolean query) {
209ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        NetworkDetail networkDetail = scanDetail.getNetworkDetail();
210ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
211ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        ANQPData anqpData = mAnqpCache.getEntry(networkDetail);
212ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
213ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        Map<Constants.ANQPElementType, ANQPElement> anqpElements =
214ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist                anqpData != null ? anqpData.getANQPElements() : null;
215ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
216ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        boolean queried = !query;
217ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        Collection<HomeSP> homeSPs = mWifiConfigStore.getHomeSPs();
218ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        Map<HomeSP, PasspointMatch> matches = new HashMap<>(homeSPs.size());
219ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        for (HomeSP homeSP : homeSPs) {
220ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            PasspointMatch match = homeSP.match(networkDetail, anqpElements);
221ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
222ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            if (match == PasspointMatch.Incomplete && networkDetail.isInterworking() && !queried) {
223ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist                if (mAnqpCache.initiate(networkDetail)) {
224ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist                    mSupplicantBridge.startANQP(scanDetail);
225ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist                }
226ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist                queried = true;
227ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            }
228ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            matches.put(homeSP, match);
229ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        }
230ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        return matches;
231ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    }
232ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
233ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    public void notifyANQPDone(Long bssid, boolean success) {
234ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        mSupplicantBridge.notifyANQPDone(bssid, success);
235ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    }
236ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
237ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    public void notifyANQPResponse(ScanDetail scanDetail,
238ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist                                   Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
239ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
240ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        updateCache(scanDetail, anqpElements);
241ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        if (anqpElements == null) {
242ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            return;
243ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        }
244ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
245ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        Map<HomeSP, PasspointMatch> matches = matchNetwork(scanDetail, false);
246ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        Log.d("HS2J", scanDetail.getSSID() + " 2nd Matches: " + toMatchString(matches));
247ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
248ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        for (Map.Entry<HomeSP, PasspointMatch> entry : matches.entrySet()) {
249ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            mMatchInfoList.add(
250ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist                    new PasspointMatchInfo(entry.getValue(), scanDetail.getNetworkDetail(),
251ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist                            entry.getKey()));
252ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        }
253ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
254ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        //mWifiStateMachine.updateScanResults(scanDetail, matches);
255ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    }
256ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
257ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    private void updateCache(ScanDetail scanDetail, Map<Constants.ANQPElementType,
258ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            ANQPElement> anqpElements)
259ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    {
260ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        NetworkDetail networkDetail = scanDetail.getNetworkDetail();
261ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
262ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        if (anqpElements == null) {
263ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            ANQPData data = mAnqpCache.getEntry(networkDetail);
264ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            if (data != null) {
265ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist                scanDetail.propagateANQPInfo(data.getANQPElements());
266ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            }
267ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            return;
268ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        }
269ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
270ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        mAnqpCache.update(networkDetail, anqpElements);
271ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
272ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        Log.d("HS2J", "Cached " + networkDetail.getBSSIDString() +
273ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist                "/" + networkDetail.getAnqpDomainID());
274ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        scanDetail.propagateANQPInfo(anqpElements);
275ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    }
276ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
277ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    private static String toMatchString(Map<HomeSP, PasspointMatch> matches) {
278ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        StringBuilder sb = new StringBuilder();
279ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        for (Map.Entry<HomeSP, PasspointMatch> entry : matches.entrySet()) {
280ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist            sb.append(' ').append(entry.getKey().getFQDN()).append("->").append(entry.getValue());
281ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        }
282ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        return sb.toString();
283ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    }
284ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
285ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    // !!! << JNo
286ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
28777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    int addToScanCache(List<ScanDetail> scanList) {
288be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        int numScanResultsKnown = 0; // Record number of scan results we knew about
289be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        WifiConfiguration associatedConfig = null;
2907b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle        boolean didAssociate = false;
2918242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle        long now = System.currentTimeMillis();
292f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
2930c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        ArrayList<NetworkKey> unknownScanResults = new ArrayList<NetworkKey>();
2940c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
29577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        for(ScanDetail scanDetail: scanList) {
29677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            ScanResult result = scanDetail.getScanResult();
2971fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng            if (result.SSID == null) continue;
298c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
299c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // Make sure we record the last time we saw this result
300f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            result.seen = System.currentTimeMillis();
301f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
302c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // Fetch the previous instance for this result
303f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult sr = scanResultCache.get(result.BSSID);
304f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (sr != null) {
3058ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0
3068ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                        && result.level == 0
3078ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                        && sr.level < -20) {
3088ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                    // A 'zero' RSSI reading is most likely a chip problem which returns
3098ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                    // an unknown RSSI, hence ignore it
3108ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                    result.level = sr.level;
3118ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                }
3128ccabb81ad304b80dc8eaa162fd322643461529bvandwalle
313931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // If there was a previous cache result for this BSSID, average the RSSI values
314c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                result.averageRssi(sr.level, sr.seen, mScanResultMaximumAge);
315f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
316c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                // Remove the previous Scan Result - this is not necessary
317f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                scanResultCache.remove(result.BSSID);
3188ccabb81ad304b80dc8eaa162fd322643461529bvandwalle            } else if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0 && result.level == 0) {
3198ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                // A 'zero' RSSI reading is most likely a chip problem which returns
3208ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                // an unknown RSSI, hence initialize it to a sane value
3218ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                result.level = mWifiConfigStore.scanResultRssiLevelPatchUp;
322e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            }
323e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle
324e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            if (!mNetworkScoreCache.isScoredNetwork(result)) {
325e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                WifiKey wkey;
326e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                // Quoted SSIDs are the only one valid at this stage
327e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                try {
328e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    wkey = new WifiKey("\"" + result.SSID + "\"", result.BSSID);
329e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                } catch (IllegalArgumentException e) {
330e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg("AutoJoinController: received badly encoded SSID=[" + result.SSID +
331e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                            "] ->skipping this network");
332e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    wkey = null;
333e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                }
334e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (wkey != null) {
335e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    NetworkKey nkey = new NetworkKey(wkey);
336e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    //if we don't know this scan result then request a score from the scorer
337e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    unknownScanResults.add(nkey);
338e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                }
339e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (VDBG) {
3407b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    String cap = "";
3417b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    if (result.capabilities != null)
3427b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                        cap = result.capabilities;
343e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg(result.SSID + " " + result.BSSID + " rssi="
3447b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                            + result.level + " cap " + cap + " is not scored");
345e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                }
3460c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            } else {
347e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (VDBG) {
3487b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    String cap = "";
3497b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    if (result.capabilities != null)
3507b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                        cap = result.capabilities;
351e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    int score = mNetworkScoreCache.getNetworkScore(result);
352e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg(result.SSID + " " + result.BSSID + " rssi="
3537b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                            + result.level + " cap " + cap + " is scored : " + score);
3540c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                }
355f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
356f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
357e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // scanResultCache.put(result.BSSID, new ScanResult(result));
358e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            scanResultCache.put(result.BSSID, result);
359be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            // Add this BSSID to the scanResultCache of a Saved WifiConfiguration
3607b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle            didAssociate = mWifiConfigStore.updateSavedNetworkHistory(result);
361f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
362be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            // If not successful, try to associate this BSSID to an existing Saved WifiConfiguration
3637b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle            if (!didAssociate) {
364be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                // We couldn't associate the scan result to a Saved WifiConfiguration
365c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                // Hence it is untrusted
366c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                result.untrusted = true;
367f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                associatedConfig = mWifiConfigStore.associateWithConfiguration(result);
3681fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng                if (associatedConfig != null && associatedConfig.SSID != null) {
369f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (VDBG) {
370f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        logDbg("addToScanCache save associated config "
3718242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle                                + associatedConfig.SSID + " with " + result.SSID
3728242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle                                + " status " + associatedConfig.autoJoinStatus
3738242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle                                + " reason " + associatedConfig.disableReason
3748242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle                                + " tsp " + associatedConfig.blackListTimestamp
3758242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle                                + " was " + (now - associatedConfig.blackListTimestamp));
376f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
377be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                    mWifiStateMachine.sendMessage(
378be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                            WifiStateMachine.CMD_AUTO_SAVE_NETWORK, associatedConfig);
3797b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    didAssociate = true;
380f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
3810d616ef3bf635dff8722e064c0be842676390ed8vandwalle            } else {
3820d616ef3bf635dff8722e064c0be842676390ed8vandwalle                // If the scan result has been blacklisted fir 18 hours -> unblacklist
3830d616ef3bf635dff8722e064c0be842676390ed8vandwalle                if ((now - result.blackListTimestamp) > loseBlackListHardMilli) {
3840d616ef3bf635dff8722e064c0be842676390ed8vandwalle                    result.setAutoJoinStatus(ScanResult.ENABLED);
3850d616ef3bf635dff8722e064c0be842676390ed8vandwalle                }
386f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
3877b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle            if (didAssociate) {
388be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                numScanResultsKnown++;
389a0708b09ad17b086c008ab100aec7143d7613c80vandwalle                result.isAutoJoinCandidate ++;
390a0708b09ad17b086c008ab100aec7143d7613c80vandwalle            } else {
391a0708b09ad17b086c008ab100aec7143d7613c80vandwalle                result.isAutoJoinCandidate = 0;
392be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            }
393f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
3940c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
3950c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        if (unknownScanResults.size() != 0) {
3960c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            NetworkKey[] newKeys =
3970c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                    unknownScanResults.toArray(new NetworkKey[unknownScanResults.size()]);
398931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Kick the score manager, we will get updated scores asynchronously
3990c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            scoreManager.requestScores(newKeys);
4000c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        }
401be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        return numScanResultsKnown;
402f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
403f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
404f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void logDbg(String message) {
4050888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle        logDbg(message, false);
406ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    }
407ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
408ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    void logDbg(String message, boolean stackTrace) {
409ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (stackTrace) {
4102f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            Log.e(TAG, message + " stack:"
411ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[2].getMethodName() + " - "
412ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[3].getMethodName() + " - "
413ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[4].getMethodName() + " - "
414ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[5].getMethodName());
415ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        } else {
4162f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            Log.e(TAG, message);
417ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        }
418f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
419f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
420931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Called directly from WifiStateMachine
421be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle    int newSupplicantResults(boolean doAutoJoin) {
422be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        int numScanResultsKnown;
42377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        List<ScanDetail> scanList = mWifiStateMachine.getScanResultsListNoCopyUnsync();
424be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        numScanResultsKnown = addToScanCache(scanList);
425f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(mScanResultMaximumAge);
426be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        if (DBG) {
427be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            logDbg("newSupplicantResults size=" + Integer.valueOf(scanResultCache.size())
4282f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        + " known=" + numScanResultsKnown + " "
4299f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                        + doAutoJoin);
430be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        }
4317806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle        if (doAutoJoin) {
4327806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            attemptAutoJoin();
4337806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle        }
434005c1ef113192f898499a407dd266393a8d6b076vandwalle        mWifiConfigStore.writeKnownNetworkHistory(false);
435be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        return numScanResultsKnown;
436f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
437f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
438f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
439931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
440931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * Not used at the moment
441f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * should be a call back from WifiScanner HAL ??
442f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * this function is not hooked and working yet, it will receive scan results from WifiScanners
443f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * with the list of IEs,then populate the capabilities by parsing the IEs and inject the scan
444f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * results as normal.
445f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     */
446f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void newHalScanResults() {
44777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        List<ScanDetail> scanList = null;//mWifiScanner.syncGetScanResultsList();
448f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String akm = WifiParser.parse_akm(null, null);
449f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        logDbg(akm);
450f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        addToScanCache(scanList);
451f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(0);
452f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
453005c1ef113192f898499a407dd266393a8d6b076vandwalle        mWifiConfigStore.writeKnownNetworkHistory(false);
454f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
455f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
456931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
457931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     *  network link quality changed, called directly from WifiTrafficPoller,
458931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * or by listening to Link Quality intent
459931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
460f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void linkQualitySignificantChange() {
461f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
462f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
463f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
464931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
465f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * compare a WifiConfiguration against the current network, return a delta score
466f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * If not associated, and the candidate will always be better
467f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * For instance if the candidate is a home network versus an unknown public wifi,
468f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * the delta will be infinite, else compare Kepler scores etc…
469b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * Negatve return values from this functions are meaningless per se, just trying to
470b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * keep them distinct for debug purpose (i.e. -1, -2 etc...)
471931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
472e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle    private int compareNetwork(WifiConfiguration candidate,
473e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                               String lastSelectedConfiguration) {
474b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (candidate == null)
475b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -3;
476b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
477f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration currentNetwork = mWifiStateMachine.getCurrentWifiConfiguration();
478b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentNetwork == null) {
479c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // Return any absurdly high score, if we are not connected there is no current
480c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // network to...
481b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle           return 1000;
482b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
483f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
484f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (candidate.configKey(true).equals(currentNetwork.configKey(true))) {
485b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -2;
486f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
487f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
488b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle        if (DBG) {
489e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            logDbg("compareNetwork will compare " + candidate.configKey()
490e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    + " with current " + currentNetwork.configKey());
491b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle        }
492833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        int order = compareWifiConfigurations(currentNetwork, candidate);
493e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle
494e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // The lastSelectedConfiguration is the configuration the user has manually selected
495e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // thru WifiPicker, or that a 3rd party app asked us to connect to via the
496e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // enableNetwork with disableOthers=true WifiManager API
497e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // As this is a direct user choice, we strongly prefer this configuration,
498e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // hence give +/-100
499e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        if ((lastSelectedConfiguration != null)
500e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                && currentNetwork.configKey().equals(lastSelectedConfiguration)) {
501e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // currentNetwork is the last selected configuration,
502e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // so keep it above connect choices (+/-60) and
503e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // above RSSI/scorer based selection of linked configuration (+/- 50)
504e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // by reducing order by -100
505e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            order = order - 100;
506e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            if (VDBG)   {
507e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("     ...and prefers -100 " + currentNetwork.configKey()
508e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " over " + candidate.configKey()
509e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " because it is the last selected -> "
510e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + Integer.toString(order));
511e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            }
512e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        } else if ((lastSelectedConfiguration != null)
513e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                && candidate.configKey().equals(lastSelectedConfiguration)) {
514e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // candidate is the last selected configuration,
515e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // so keep it above connect choices (+/-60) and
516e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // above RSSI/scorer based selection of linked configuration (+/- 50)
517e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // by increasing order by +100
518e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            order = order + 100;
519e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            if (VDBG)   {
520e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("     ...and prefers +100 " + candidate.configKey()
521e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " over " + currentNetwork.configKey()
522e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " because it is the last selected -> "
523e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + Integer.toString(order));
524e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            }
525e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        }
526e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle
527ede507649471f1113e9e1919812115ca5a6bc0c8vandwalle        return order;
528f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
529f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
530ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    /**
531ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * update the network history fields fo that configuration
532ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if userTriggered, we mark the configuration as "non selfAdded" since the user has seen it
533ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * and took over management
534ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if it is a "connect", remember which network were there at the point of the connect, so
535ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * as those networks get a relative lower score than the selected configuration
53662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle     *
537ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param netId
538ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param userTriggered : if the update come from WiFiManager
539ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param connect : if the update includes a connect
540931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
54162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle    public void updateConfigurationHistory(int netId, boolean userTriggered, boolean connect) {
542f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration selected = mWifiConfigStore.getWifiConfiguration(netId);
543f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (selected == null) {
544c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory nid=" + netId + " no selected configuration!");
545f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return;
546f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
547f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
548e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        if (selected.SSID == null) {
549c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory nid=" + netId +
550c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    " no SSID in selected configuration!");
551e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            return;
552e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        }
553e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
55462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        if (userTriggered) {
555931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Reenable autojoin for this network,
55662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            // since the user want to connect to this configuration
55727355a942653264388e909a4276196ee63e57811vandwalle            selected.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
55862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            selected.selfAdded = false;
559e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            selected.dirty = true;
56062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        }
561f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
562992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (DBG && userTriggered) {
563f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (selected.connectChoices != null) {
564ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
565f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + Integer.toString(netId) + " now: "
566992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(selected.connectChoices.size())
567992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
568f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
569ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
570992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(netId)
571992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
572f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
573f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
574f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
575ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (connect && userTriggered) {
576ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            boolean found = false;
5772451dbcc4f9641df188326215b204b798eb70c46vandwalle            int choice = 0;
578c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            int size = 0;
5799f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
5809f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // Reset the triggered disabled count, because user wanted to connect to this
5819f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // configuration, and we were not.
5829f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableLowRSSI = 0;
5839f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableBadRSSI = 0;
5849f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableNotHighRSSI = 0;
5859f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredJoinAttempts++;
5869f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
58762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            List<WifiConfiguration> networks =
58862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    mWifiConfigStore.getRecentConfiguredNetworks(12000, false);
589c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (networks != null) size = networks.size();
590c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory found " + size + " networks");
59162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            if (networks != null) {
59262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                for (WifiConfiguration config : networks) {
593992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    if (DBG) {
594992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        logDbg("updateConfigurationHistory got " + config.SSID + " nid="
595992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                                + Integer.toString(config.networkId));
596992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    }
597f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
59862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (selected.configKey(true).equals(config.configKey(true))) {
599ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        found = true;
60062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        continue;
60162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
602f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
6032451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // Compare RSSI values so as to evaluate the strength of the user preference
6042451dbcc4f9641df188326215b204b798eb70c46vandwalle                    int order = compareWifiConfigurationsRSSI(config, selected, null);
6052451dbcc4f9641df188326215b204b798eb70c46vandwalle
6062451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (order < -30) {
6072451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is worse than the visible configuration
6082451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence register a strong choice so as autojoin cannot override this
6092451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // for instance, the user has select a network
6102451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // with 1 bar over a network with 3 bars...
6112451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 60;
6122451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order < -20) {
6132451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 50;
6142451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order < -10) {
6152451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 40;
6162f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    } else if (order < 20) {
6172451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is about same or has a slightly better RSSI
6182451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence register a weaker choice, here a difference of at least +/-30 in
6192451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // RSSI comparison triggered by autoJoin will override the choice
6202451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 30;
6212f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    } else {
6222451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is better than the visible configuration
6232451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence we do not know if the user prefers this configuration strongly
6242451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 20;
62562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
626f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
627931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // The selected configuration was preferred over a recently seen config
628931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // hence remember the user's choice:
629931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // add the recently seen config to the selected's connectChoices array
630ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
631ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    if (selected.connectChoices == null) {
632ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        selected.connectChoices = new HashMap<String, Integer>();
633ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    }
634ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
635ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    logDbg("updateConfigurationHistory add a choice " + selected.configKey(true)
6360888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                            + " over " + config.configKey(true)
6372451dbcc4f9641df188326215b204b798eb70c46vandwalle                            + " choice " + Integer.toString(choice));
638cf5b8eb8a08c45bd4a82f1f4bb789c8a1b08744fvandwalle
6392451dbcc4f9641df188326215b204b798eb70c46vandwalle                    Integer currentChoice = selected.connectChoices.get(config.configKey(true));
6402f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    if (currentChoice != null) {
6412f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // User has made this choice multiple time in a row, so bump up a lot
6422f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        choice += currentChoice.intValue();
6432451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
6442f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // Add the visible config to the selected's connect choice list
6452f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    selected.connectChoices.put(config.configKey(true), choice);
646f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
64762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (config.connectChoices != null) {
648ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        if (VDBG) {
649ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                            logDbg("updateConfigurationHistory will remove "
65062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                    + selected.configKey(true) + " from " + config.configKey(true));
651ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        }
652931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Remove the selected from the recently seen config's connectChoice list
65362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        config.connectChoices.remove(selected.configKey(true));
6540888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle
6550888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        if (selected.linkedConfigurations != null) {
656931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                           // Remove the selected's linked configuration from the
657931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                           // recently seen config's connectChoice list
6580888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           for (String key : selected.linkedConfigurations.keySet()) {
6590888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                               config.connectChoices.remove(key);
6600888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           }
6610888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        }
66262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
663ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                }
664ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                if (found == false) {
6652451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // We haven't found the configuration that the user just selected in our
6662451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // scan cache.
6672451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // In that case we will need a new scan before attempting to connect to this
6682451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // configuration anyhow and thus we can process the scan results then.
669ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     logDbg("updateConfigurationHistory try to connect to an old network!! : "
670ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                             + selected.configKey());
67162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
672f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
67362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                if (selected.connectChoices != null) {
67462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (VDBG)
675ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        logDbg("updateConfigurationHistory " + Integer.toString(netId)
67662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                + " now: " + Integer.toString(selected.connectChoices.size()));
67762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
678f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
679f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
680992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle
681931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // TODO: write only if something changed
682992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (userTriggered || connect) {
683005c1ef113192f898499a407dd266393a8d6b076vandwalle            mWifiConfigStore.writeKnownNetworkHistory(false);
684992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        }
685f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
686f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
6872451dbcc4f9641df188326215b204b798eb70c46vandwalle    int getConnectChoice(WifiConfiguration source, WifiConfiguration target) {
6882451dbcc4f9641df188326215b204b798eb70c46vandwalle        Integer choice = null;
6892451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (source == null || target == null) {
6902451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
691f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
692f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
6932451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (source.connectChoices != null
6942451dbcc4f9641df188326215b204b798eb70c46vandwalle                && source.connectChoices.containsKey(target.configKey(true))) {
6952451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = source.connectChoices.get(target.configKey(true));
6962451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else if (source.linkedConfigurations != null) {
697f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            for (String key : source.linkedConfigurations.keySet()) {
698f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(key);
699f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (config != null) {
700f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (config.connectChoices != null) {
7012451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = config.connectChoices.get(target.configKey(true));
702f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
703f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
704f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
7052451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
7062451dbcc4f9641df188326215b204b798eb70c46vandwalle
7072451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (choice == null) {
7082451dbcc4f9641df188326215b204b798eb70c46vandwalle            //We didn't find the connect choice
7092451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
7102451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else {
7112451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice.intValue() < 0) {
7122451dbcc4f9641df188326215b204b798eb70c46vandwalle                choice = 20; // Compatibility with older files
7132451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
7142451dbcc4f9641df188326215b204b798eb70c46vandwalle            return choice.intValue();
7152451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
7162451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
7172451dbcc4f9641df188326215b204b798eb70c46vandwalle
718815788ba7838fc54310baed3deb9b95548e0ce69vandwalle    int compareWifiConfigurationsFromVisibility(WifiConfiguration a, int aRssiBoost,
719815788ba7838fc54310baed3deb9b95548e0ce69vandwalle             WifiConfiguration b, int bRssiBoost) {
7202451dbcc4f9641df188326215b204b798eb70c46vandwalle
721815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        int aRssiBoost5 = 0; // 5GHz RSSI boost to apply for purpose band selection (5GHz pref)
722815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        int bRssiBoost5 = 0; // 5GHz RSSI boost to apply for purpose band selection (5GHz pref)
723815788ba7838fc54310baed3deb9b95548e0ce69vandwalle
724815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        int aScore = 0;
725815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        int bScore = 0;
726815788ba7838fc54310baed3deb9b95548e0ce69vandwalle
727815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        boolean aPrefers5GHz = false;
728815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        boolean bPrefers5GHz = false;
7294dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
7302451dbcc4f9641df188326215b204b798eb70c46vandwalle        /**
731815788ba7838fc54310baed3deb9b95548e0ce69vandwalle         * Calculate a boost to apply to RSSI value of configuration we want to join on 5GHz:
732815788ba7838fc54310baed3deb9b95548e0ce69vandwalle         * Boost RSSI value of 5GHz bands iff the base value is better than threshold,
733815788ba7838fc54310baed3deb9b95548e0ce69vandwalle         * penalize the RSSI value of 5GHz band iff the base value is lower than threshold
7342451dbcc4f9641df188326215b204b798eb70c46vandwalle         * This implements band preference where we prefer 5GHz if RSSI5 is good enough, whereas
7352451dbcc4f9641df188326215b204b798eb70c46vandwalle         * we prefer 2.4GHz otherwise.
7362451dbcc4f9641df188326215b204b798eb70c46vandwalle         */
737815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        aRssiBoost5 = rssiBoostFrom5GHzRssi(a.visibility.rssi5, a.configKey() + "->");
738815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        bRssiBoost5 = rssiBoostFrom5GHzRssi(b.visibility.rssi5, b.configKey() + "->");
7392451dbcc4f9641df188326215b204b798eb70c46vandwalle
740815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // Select which band to use for a
741f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        if (a.visibility.rssi5 + aRssiBoost5 > a.visibility.rssi24) {
7422451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Prefer a's 5GHz
743815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            aPrefers5GHz = true;
744815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        }
745815788ba7838fc54310baed3deb9b95548e0ce69vandwalle
746815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // Select which band to use for b
747815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        if (b.visibility.rssi5 + bRssiBoost5 > b.visibility.rssi24) {
748815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            // Prefer b's 5GHz
749815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            bPrefers5GHz = true;
750815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        }
751815788ba7838fc54310baed3deb9b95548e0ce69vandwalle
752815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        if (aPrefers5GHz) {
753815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            if (bPrefers5GHz) {
754815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // If both a and b are on 5GHz then we don't apply the 5GHz RSSI boost to either
755815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // one, but directly compare the RSSI values, this improves stability,
756815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // since the 5GHz RSSI boost can introduce large fluctuations
757815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                aScore = a.visibility.rssi5 + aRssiBoost;
758815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            } else {
759815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // If only a is on 5GHz, then apply the 5GHz preference boost to a
760815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                aScore = a.visibility.rssi5 + aRssiBoost + aRssiBoost5;
761815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            }
7622451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else {
763815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            aScore = a.visibility.rssi24 + aRssiBoost;
764f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
7652451dbcc4f9641df188326215b204b798eb70c46vandwalle
766815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        if (bPrefers5GHz) {
767815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            if (aPrefers5GHz) {
768815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // If both a and b are on 5GHz then we don't apply the 5GHz RSSI boost to either
769815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // one, but directly compare the RSSI values, this improves stability,
770815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // since the 5GHz RSSI boost can introduce large fluctuations
771815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                bScore = b.visibility.rssi5 + bRssiBoost;
772815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            } else {
773815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // If only b is on 5GHz, then apply the 5GHz preference boost to b
774815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                bScore = b.visibility.rssi5 + bRssiBoost + bRssiBoost5;
775815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            }
776815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        } else {
777815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            bScore = b.visibility.rssi24 + bRssiBoost;
778815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        }
779815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        if (VDBG) {
780815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            logDbg("        " + a.configKey() + " is5=" + aPrefers5GHz + " score=" + aScore
781f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    + " " + b.configKey() + " is5=" + bPrefers5GHz + " score=" + bScore);
782815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        }
783f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle
784f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        // Debug only, record RSSI comparison parameters
785f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        if (a.visibility != null) {
786f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle            a.visibility.score = aScore;
787f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle            a.visibility.currentNetworkBoost = aRssiBoost;
788f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle            a.visibility.bandPreferenceBoost = aRssiBoost5;
789f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        }
790f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        if (b.visibility != null) {
791f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle            b.visibility.score = bScore;
792f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle            b.visibility.currentNetworkBoost = bRssiBoost;
793f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle            b.visibility.bandPreferenceBoost = bRssiBoost5;
794f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        }
795f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle
796815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // Compare a and b
797815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // If a score is higher then a > b and the order is descending (negative)
798815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // If b score is higher then a < b and the order is ascending (positive)
799815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        return bScore - aScore;
800f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
801f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
8022451dbcc4f9641df188326215b204b798eb70c46vandwalle    // Compare WifiConfiguration by RSSI, and return a comparison value in the range [-50, +50]
8032451dbcc4f9641df188326215b204b798eb70c46vandwalle    // The result represents "approximately" an RSSI difference measured in dBM
8042451dbcc4f9641df188326215b204b798eb70c46vandwalle    // Adjusted with various parameters:
8052451dbcc4f9641df188326215b204b798eb70c46vandwalle    // +) current network gets a +15 boost
8062451dbcc4f9641df188326215b204b798eb70c46vandwalle    // +) 5GHz signal, if they are strong enough, get a +15 or +25 boost, representing the
8072451dbcc4f9641df188326215b204b798eb70c46vandwalle    // fact that at short range we prefer 5GHz band as it is cleaner of interference and
8082451dbcc4f9641df188326215b204b798eb70c46vandwalle    // provides for wider channels
8092451dbcc4f9641df188326215b204b798eb70c46vandwalle    int compareWifiConfigurationsRSSI(WifiConfiguration a, WifiConfiguration b,
8102451dbcc4f9641df188326215b204b798eb70c46vandwalle                                      String currentConfiguration) {
811f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
8122451dbcc4f9641df188326215b204b798eb70c46vandwalle
8132451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Boost used so as to favor current config
8142451dbcc4f9641df188326215b204b798eb70c46vandwalle        int aRssiBoost = 0;
8152451dbcc4f9641df188326215b204b798eb70c46vandwalle        int bRssiBoost = 0;
8162451dbcc4f9641df188326215b204b798eb70c46vandwalle
8172451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreA;
8182451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreB;
8192451dbcc4f9641df188326215b204b798eb70c46vandwalle
8202451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Retrieve the visibility
821f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility astatus = a.visibility;
822f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility bstatus = b.visibility;
823f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (astatus == null || bstatus == null) {
8242451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Error visibility wasn't set
825b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurations NULL band status!");
826f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 0;
827f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
8282451dbcc4f9641df188326215b204b798eb70c46vandwalle
8292451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply Hysteresis, boost RSSI of current configuration
8302451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (null != currentConfiguration) {
8312451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (a.configKey().equals(currentConfiguration)) {
83293a1fddee50a244d31036cddae6b7db6630fd93dvandwalle                aRssiBoost = mWifiConfigStore.currentNetworkBoost;
8332451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (b.configKey().equals(currentConfiguration)) {
83493a1fddee50a244d31036cddae6b7db6630fd93dvandwalle                bRssiBoost = mWifiConfigStore.currentNetworkBoost;
8352451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
8362451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
8372451dbcc4f9641df188326215b204b798eb70c46vandwalle
8382451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG)  {
839b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsRSSI: " + a.configKey()
840f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    + " rssi=" + Integer.toString(astatus.rssi24)
841c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + "," + Integer.toString(astatus.rssi5)
8422451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " boost=" + Integer.toString(aRssiBoost)
843f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    + " " + b.configKey() + " rssi="
844c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + Integer.toString(bstatus.rssi24) + ","
845c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + Integer.toString(bstatus.rssi5)
8462451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " boost=" + Integer.toString(bRssiBoost)
8472451dbcc4f9641df188326215b204b798eb70c46vandwalle            );
848f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
8492451dbcc4f9641df188326215b204b798eb70c46vandwalle
850815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        order = compareWifiConfigurationsFromVisibility(a, aRssiBoost, b, bRssiBoost);
8512451dbcc4f9641df188326215b204b798eb70c46vandwalle
8522451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Normalize the order to [-50, +50]
8532451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (order > 50) order = 50;
8542451dbcc4f9641df188326215b204b798eb70c46vandwalle        else if (order < -50) order = -50;
8552451dbcc4f9641df188326215b204b798eb70c46vandwalle
8562451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
8572451dbcc4f9641df188326215b204b798eb70c46vandwalle            String prefer = " = ";
8582451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (order > 0) {
8592451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " < "; // Ascending
8602451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (order < 0) {
8612451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " > "; // Descending
8622451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
863b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsRSSI " + a.configKey()
8642451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + a.visibility.rssi24
8652451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.rssi5
8662451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + a.visibility.num24
8672451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.num5 + ")"
8682451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + prefer + b.configKey()
8692451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + b.visibility.rssi24
8702451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.rssi5
8712451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + b.visibility.num24
8722451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.num5 + ")"
8732451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " -> " + order);
8742451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
8752451dbcc4f9641df188326215b204b798eb70c46vandwalle
876f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
877f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
878f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
879833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle    /**
880833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle     * b/18490330 only use scorer for untrusted networks
881833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle     *
8822451dbcc4f9641df188326215b204b798eb70c46vandwalle    int compareWifiConfigurationsWithScorer(WifiConfiguration a, WifiConfiguration b) {
8832451dbcc4f9641df188326215b204b798eb70c46vandwalle
88481c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson        boolean aIsActive = false;
88581c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson        boolean bIsActive = false;
8862451dbcc4f9641df188326215b204b798eb70c46vandwalle
8872451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply Hysteresis : boost RSSI of current configuration before
8882451dbcc4f9641df188326215b204b798eb70c46vandwalle        // looking up the score
8892451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (null != mCurrentConfigurationKey) {
8902451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (a.configKey().equals(mCurrentConfigurationKey)) {
89181c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                aIsActive = true;
8922451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (b.configKey().equals(mCurrentConfigurationKey)) {
89381c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                bIsActive = true;
8942451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
8952451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
896833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        int scoreA = getConfigNetworkScore(a, mScanResultAutoJoinAge, aIsActive);
897833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        int scoreB = getConfigNetworkScore(b, mScanResultAutoJoinAge, bIsActive);
8982451dbcc4f9641df188326215b204b798eb70c46vandwalle
8992451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Both configurations need to have a score for the scorer to be used
9002451dbcc4f9641df188326215b204b798eb70c46vandwalle        // ...and the scores need to be different:-)
9012451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (scoreA == WifiNetworkScoreCache.INVALID_NETWORK_SCORE
9022451dbcc4f9641df188326215b204b798eb70c46vandwalle                || scoreB == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
903e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            if (VDBG)  {
904b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurationsWithScorer no-scores: "
905e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                        + a.configKey()
906e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                        + " "
907e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                        + b.configKey());
908e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            }
9092451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
9102451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
9112451dbcc4f9641df188326215b204b798eb70c46vandwalle
9122451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
9132451dbcc4f9641df188326215b204b798eb70c46vandwalle            String prefer = " = ";
9142451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (scoreA < scoreB) {
9152451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " < ";
9162451dbcc4f9641df188326215b204b798eb70c46vandwalle            } if (scoreA > scoreB) {
9172451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " > ";
9182451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
919b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsWithScorer " + a.configKey()
9202451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + a.visibility.rssi24
9212451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.rssi5
9222451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + a.visibility.num24
9232451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.num5 + ")"
924e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    + " sc=" + scoreA
9252451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + prefer + b.configKey()
9262451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + b.visibility.rssi24
9272451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.rssi5
9282451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + b.visibility.num24
9292451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.num5 + ")"
930e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    + " sc=" + scoreB
9312451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " -> " + Integer.toString(scoreB - scoreA));
9322451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
933c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
9342451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If scoreA > scoreB, the comparison is descending hence the return value is negative
9352451dbcc4f9641df188326215b204b798eb70c46vandwalle        return scoreB - scoreA;
9362451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
937833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle     */
9382451dbcc4f9641df188326215b204b798eb70c46vandwalle
939f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    int compareWifiConfigurations(WifiConfiguration a, WifiConfiguration b) {
940f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
941f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        boolean linked = false;
942f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
943453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if ((a.linkedConfigurations != null) && (b.linkedConfigurations != null)
944453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (a.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)
945453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (b.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)) {
9462451dbcc4f9641df188326215b204b798eb70c46vandwalle            if ((a.linkedConfigurations.get(b.configKey(true)) != null)
9472451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && (b.linkedConfigurations.get(a.configKey(true)) != null)) {
948f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                linked = true;
949f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
950f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
951f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
952f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (a.ephemeral && b.ephemeral == false) {
953f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
954b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurations ephemeral and prefers " + b.configKey()
955453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + a.configKey());
956f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
957931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            return 1; // b is of higher priority - ascending
958f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
959f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (b.ephemeral && a.ephemeral == false) {
960f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
961b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurations ephemeral and prefers " + a.configKey()
962453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey());
963f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
964931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            return -1; // a is of higher priority - descending
965f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
966f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
9672451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply RSSI, in the range [-5, +5]
9682451dbcc4f9641df188326215b204b798eb70c46vandwalle        // after band adjustment, +n difference roughly corresponds to +10xn dBm
9692451dbcc4f9641df188326215b204b798eb70c46vandwalle        order = order + compareWifiConfigurationsRSSI(a, b, mCurrentConfigurationKey);
970f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
9712451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If the configurations are not linked, compare by user's choice, only a
9722451dbcc4f9641df188326215b204b798eb70c46vandwalle        // very high RSSI difference can then override the choice
9732451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (!linked) {
9742451dbcc4f9641df188326215b204b798eb70c46vandwalle            int choice;
975f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
9762451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = getConnectChoice(a, b);
9772451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice > 0) {
978931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of higher priority - descending
9792451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = order - choice;
980f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG) {
981b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers " + a.configKey()
982453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + " over " + b.configKey()
983b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " due to user choice of " + choice
984b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " order -> " + Integer.toString(order));
985f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
986f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                if (a.visibility != null) {
987f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    a.visibility.lastChoiceBoost = choice;
988f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    a.visibility.lastChoiceConfig = b.configKey();
989f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                }
9902451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
9912451dbcc4f9641df188326215b204b798eb70c46vandwalle
9922451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = getConnectChoice(b, a);
9932451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice > 0) {
994931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of lower priority - ascending
9952451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = order + choice;
9964dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                if (VDBG) {
997b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers " + b.configKey() + " over "
998b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + a.configKey() + " due to user choice of " + choice
999b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " order ->" + Integer.toString(order));
1000f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1001f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                if (b.visibility != null) {
1002f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    b.visibility.lastChoiceBoost = choice;
1003f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    b.visibility.lastChoiceConfig = a.configKey();
1004f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                }
1005f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1006f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1007ede1310be531a84faa08f02c3fd243448dd936ddvandwalle
1008f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order == 0) {
1009931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // We don't know anything - pick the last seen i.e. K behavior
1010931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // we should do this only for recently picked configurations
1011f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (a.priority > b.priority) {
1012931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of higher priority - descending
10132451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (VDBG) {
1014b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers -1 " + a.configKey() + " over "
1015453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + b.configKey() + " due to priority");
1016f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1017f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1018f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                order = -1;
1019f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else if (a.priority < b.priority) {
1020931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of lower priority - ascending
10212451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (VDBG) {
1022b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers +1 " + b.configKey() + " over "
1023453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + a.configKey() + " due to priority");
1024f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
10252451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = 1;
1026f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1027f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1028f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1029f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String sorder = " == ";
1030931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        if (order > 0) {
1031f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " < ";
1032931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        } else if (order < 0) {
1033f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " > ";
1034931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        }
1035f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
10362451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
1037b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("compareWifiConfigurations: " + a.configKey() + sorder
1038453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    + b.configKey() + " order " + Integer.toString(order));
1039f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1040f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1041f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
1042f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
1043f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1044c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    boolean isBadCandidate(int rssi5, int rssi24) {
1045c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        return (rssi5 < -80 && rssi24 < -90);
1046c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    }
1047c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
1048833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle    /*
1049c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    int compareWifiConfigurationsTop(WifiConfiguration a, WifiConfiguration b) {
1050c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        int scorerOrder = compareWifiConfigurationsWithScorer(a, b);
1051c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        int order = compareWifiConfigurations(a, b);
1052c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
1053c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        if (scorerOrder * order < 0) {
1054b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (VDBG) {
1055b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    -> compareWifiConfigurationsTop: " +
1056b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                        "scorer override " + scorerOrder + " " + order);
1057b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1058c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // For debugging purpose, remember that an override happened
1059c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // during that autojoin Attempt
1060c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            didOverride = true;
1061c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            a.numScorerOverride++;
1062c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            b.numScorerOverride++;
1063c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        }
1064c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
1065c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        if (scorerOrder != 0) {
1066c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // If the scorer came up with a result then use the scorer's result, else use
1067c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // the order provided by the base comparison function
1068c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            order = scorerOrder;
1069c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        }
1070c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        return order;
1071c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    }
1072833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle    */
1073c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
10749f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle    public int rssiBoostFrom5GHzRssi(int rssi, String dbg) {
10750eebae7334d6129f7ca1344e4b20199794994358vandwalle        if (!mWifiConfigStore.enable5GHzPreference) {
10760eebae7334d6129f7ca1344e4b20199794994358vandwalle            return 0;
10770eebae7334d6129f7ca1344e4b20199794994358vandwalle        }
1078e67ec726c07410073575473c0f50dc737629f5davandwalle        if (rssi
107977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                > mWifiConfigStore.bandPreferenceBoostThreshold5.get()) {
1080e67ec726c07410073575473c0f50dc737629f5davandwalle            // Boost by 2 dB for each point
1081e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Start boosting at -65
1082e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Boost by 20 if above -55
1083e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Boost by 40 if abore -45
10840eebae7334d6129f7ca1344e4b20199794994358vandwalle            int boost = mWifiConfigStore.bandPreferenceBoostFactor5
108577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    *(rssi - mWifiConfigStore.bandPreferenceBoostThreshold5.get());
1086e67ec726c07410073575473c0f50dc737629f5davandwalle            if (boost > 50) {
1087815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // 50 dB boost allows jumping from 2.4 to 5GHz
1088e67ec726c07410073575473c0f50dc737629f5davandwalle                // consistently
1089e67ec726c07410073575473c0f50dc737629f5davandwalle                boost = 50;
1090e67ec726c07410073575473c0f50dc737629f5davandwalle            }
10919f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            if (VDBG && dbg != null) {
1092f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                logDbg("        " + dbg + ":    rssi5 " + rssi + " 5GHz-boost " + boost);
10939f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            }
1094e67ec726c07410073575473c0f50dc737629f5davandwalle            return boost;
1095e67ec726c07410073575473c0f50dc737629f5davandwalle        }
1096e67ec726c07410073575473c0f50dc737629f5davandwalle
1097e67ec726c07410073575473c0f50dc737629f5davandwalle        if (rssi
109877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                < mWifiConfigStore.bandPreferencePenaltyThreshold5.get()) {
10990eebae7334d6129f7ca1344e4b20199794994358vandwalle            // penalize if < -75
11000eebae7334d6129f7ca1344e4b20199794994358vandwalle            int boost = mWifiConfigStore.bandPreferencePenaltyFactor5
110177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    *(rssi - mWifiConfigStore.bandPreferencePenaltyThreshold5.get());
11020eebae7334d6129f7ca1344e4b20199794994358vandwalle            return boost;
1103e67ec726c07410073575473c0f50dc737629f5davandwalle        }
1104e67ec726c07410073575473c0f50dc737629f5davandwalle        return 0;
1105e67ec726c07410073575473c0f50dc737629f5davandwalle    }
1106c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        /**
1107e67ec726c07410073575473c0f50dc737629f5davandwalle         * attemptRoam() function implements the core of the same SSID switching algorithm
1108e67ec726c07410073575473c0f50dc737629f5davandwalle         *
1109e67ec726c07410073575473c0f50dc737629f5davandwalle         * Run thru all recent scan result of a WifiConfiguration and select the
1110e67ec726c07410073575473c0f50dc737629f5davandwalle         * best one.
1111c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle         */
1112e67ec726c07410073575473c0f50dc737629f5davandwalle    public ScanResult attemptRoam(ScanResult a,
1113e67ec726c07410073575473c0f50dc737629f5davandwalle                                  WifiConfiguration current, int age, String currentBSSID) {
1114b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current == null) {
1115b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
1116b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam not associated");
1117b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
1118e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
11194dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
1120b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current.scanResultCache == null) {
1121b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
1122b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam no scan cache");
1123b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
1124e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
11254dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
1126b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle        if (current.scanResultCache.size() > 6) {
1127b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
1128c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptRoam scan cache size "
1129c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + current.scanResultCache.size() + " --> bail");
1130b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
1131931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Implement same SSID roaming only for configurations
1132c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            // that have less than 4 BSSIDs
1133e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
11344dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
1135b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
11362f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle        if (current.BSSID != null && !current.BSSID.equals("any")) {
1137b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (DBG)   {
11382f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                logDbg("attemptRoam() BSSID is set "
11392f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        + current.BSSID + " -> bail");
1140b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
1141e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
11424dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
11434dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1144931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Determine which BSSID we want to associate to, taking account
1145c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle        // relative strength of 5 and 2.4 GHz BSSIDs
11462451dbcc4f9641df188326215b204b798eb70c46vandwalle        long nowMs = System.currentTimeMillis();
11474dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
114897b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle        for (ScanResult b : current.scanResultCache.values()) {
114997b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int bRssiBoost5 = 0;
115097b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int aRssiBoost5 = 0;
115197b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int bRssiBoost = 0;
115297b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int aRssiBoost = 0;
1153931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            if ((b.seen == 0) || (b.BSSID == null)
11540d616ef3bf635dff8722e064c0be842676390ed8vandwalle                    || ((nowMs - b.seen) > age)
1155e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    || b.autoJoinStatus != ScanResult.ENABLED
1156e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    || b.numIpConfigFailures > 8) {
11574dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
11583a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
11594dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1160931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Pick first one
11614dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (a == null) {
11624dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                a = b;
11634dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
11644dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
11654dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1166e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            if (b.numIpConfigFailures < (a.numIpConfigFailures - 1)) {
1167e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                // Prefer a BSSID that doesn't have less number of Ip config failures
1168e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("attemptRoam: "
1169e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + b.BSSID + " rssi=" + b.level + " ipfail=" +b.numIpConfigFailures
1170e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " freq=" + b.frequency
1171e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " > "
1172e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + a.BSSID + " rssi=" + a.level + " ipfail=" +a.numIpConfigFailures
1173e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " freq=" + a.frequency);
1174e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                a = b;
1175e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                continue;
1176e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            }
1177e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle
11782451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Apply hysteresis: we favor the currentBSSID by giving it a boost
11797806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentBSSID != null && currentBSSID.equals(b.BSSID)) {
1180931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Reduce the benefit of hysteresis if RSSI <= -75
118177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                if (b.level <= mWifiConfigStore.bandPreferencePenaltyThreshold5.get()) {
11820eebae7334d6129f7ca1344e4b20199794994358vandwalle                    bRssiBoost = mWifiConfigStore.associatedHysteresisLow;
1183c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
11840eebae7334d6129f7ca1344e4b20199794994358vandwalle                    bRssiBoost = mWifiConfigStore.associatedHysteresisHigh;
1185c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
11864dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
11877806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentBSSID != null && currentBSSID.equals(a.BSSID)) {
118877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                if (a.level <= mWifiConfigStore.bandPreferencePenaltyThreshold5.get()) {
1189931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Reduce the benefit of hysteresis if RSSI <= -75
11900eebae7334d6129f7ca1344e4b20199794994358vandwalle                    aRssiBoost = mWifiConfigStore.associatedHysteresisLow;
1191c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
11920eebae7334d6129f7ca1344e4b20199794994358vandwalle                    aRssiBoost = mWifiConfigStore.associatedHysteresisHigh;
1193c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
11944dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
11952451dbcc4f9641df188326215b204b798eb70c46vandwalle
119697b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            // Favor 5GHz: give a boost to 5GHz BSSIDs, with a slightly progressive curve
11972451dbcc4f9641df188326215b204b798eb70c46vandwalle            //   Boost the BSSID if it is on 5GHz, above a threshold
11982451dbcc4f9641df188326215b204b798eb70c46vandwalle            //   But penalize it if it is on 5GHz and below threshold
119997b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //
120097b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   With he current threshold values, 5GHz network with RSSI above -55
120197b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   Are given a boost of 30DB which is enough to overcome the current BSSID
120297b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   hysteresis (+14) plus 2.4/5 GHz signal strength difference on most cases
12039f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            //
12049f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // The "current BSSID" Boost must be added to the BSSID's level so as to introduce\
12059f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // soem amount of hysteresis
1206e67ec726c07410073575473c0f50dc737629f5davandwalle            if (b.is5GHz()) {
12079f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                bRssiBoost5 = rssiBoostFrom5GHzRssi(b.level + bRssiBoost, b.BSSID);
12084dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
1209e67ec726c07410073575473c0f50dc737629f5davandwalle            if (a.is5GHz()) {
12109f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                aRssiBoost5 = rssiBoostFrom5GHzRssi(a.level + aRssiBoost, a.BSSID);
12114dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
12124dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
12134dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (VDBG)  {
1214c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                String comp = " < ";
1215c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
1216c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    comp = " > ";
1217c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
12184dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                logDbg("attemptRoam: "
1219c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + b.BSSID + " rssi=" + b.level + " boost=" + Integer.toString(bRssiBoost)
122097b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                        + "/" + Integer.toString(bRssiBoost5) + " freq=" + b.frequency
122197b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                        + comp
1222c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + a.BSSID + " rssi=" + a.level + " boost=" + Integer.toString(aRssiBoost)
1223c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + "/" + Integer.toString(aRssiBoost5) + " freq=" + a.frequency);
1224c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            }
1225c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle
12262451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Compare the RSSIs after applying the hysteresis boost and the 5GHz
12272451dbcc4f9641df188326215b204b798eb70c46vandwalle            // boost if applicable
1228c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
1229931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // b is the better BSSID
1230c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                a = b;
12314dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
12324dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
12333a2a3d226881cce8a4e511302231d843b0def303vandwalle        if (a != null) {
12343a2a3d226881cce8a4e511302231d843b0def303vandwalle            if (VDBG)  {
12357806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                StringBuilder sb = new StringBuilder();
1236e67ec726c07410073575473c0f50dc737629f5davandwalle                sb.append("attemptRoam: " + current.configKey() +
1237e67ec726c07410073575473c0f50dc737629f5davandwalle                        " Found " + a.BSSID + " rssi=" + a.level + " freq=" + a.frequency);
12387806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                if (currentBSSID != null) {
12397806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                    sb.append(" Current: " + currentBSSID);
12407806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                }
12417806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                sb.append("\n");
12427806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                logDbg(sb.toString());
12433a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
12444dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
12453a2a3d226881cce8a4e511302231d843b0def303vandwalle        return a;
12464dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    }
12474dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1248931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
12492451dbcc4f9641df188326215b204b798eb70c46vandwalle     * getNetworkScore()
12502451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
12512451dbcc4f9641df188326215b204b798eb70c46vandwalle     * if scorer is present, get the network score of a WifiConfiguration
12522451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
12532451dbcc4f9641df188326215b204b798eb70c46vandwalle     * Note: this should be merge with setVisibility
12542451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
12552451dbcc4f9641df188326215b204b798eb70c46vandwalle     * @param config
12562451dbcc4f9641df188326215b204b798eb70c46vandwalle     * @return score
12572451dbcc4f9641df188326215b204b798eb70c46vandwalle     */
125881c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson    int getConfigNetworkScore(WifiConfiguration config, int age, boolean isActive) {
12592451dbcc4f9641df188326215b204b798eb70c46vandwalle
12602451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (mNetworkScoreCache == null) {
1261e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (VDBG) {
1262b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("       getConfigNetworkScore for " + config.configKey()
1263e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + "  -> no scorer, hence no scores");
1264e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
12651db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            return WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
12661db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        }
12671db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        if (config.scanResultCache == null) {
1268e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (VDBG) {
1269b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("       getConfigNetworkScore for " + config.configKey()
1270e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " -> no scan cache");
1271e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
12721db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            return WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
12732451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
12742451dbcc4f9641df188326215b204b798eb70c46vandwalle
12752451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Get current date
12762451dbcc4f9641df188326215b204b798eb70c46vandwalle        long nowMs = System.currentTimeMillis();
12772451dbcc4f9641df188326215b204b798eb70c46vandwalle
12781db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        int startScore = -10000;
12791db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle
12802451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Run thru all cached scan results
12811db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        for (ScanResult result : config.scanResultCache.values()) {
12822451dbcc4f9641df188326215b204b798eb70c46vandwalle            if ((nowMs - result.seen) < age) {
128381c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                int sc = mNetworkScoreCache.getNetworkScore(result, isActive);
12841db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle                if (sc > startScore) {
12851db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle                    startScore = sc;
12862451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
12872451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
12882451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
12891db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        if (startScore == -10000) {
12901db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            startScore = WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
12911db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        }
1292e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle        if (VDBG) {
1293e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (startScore == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
1294b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    getConfigNetworkScore for " + config.configKey()
1295e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " -> no available score");
1296e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            } else {
1297b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    getConfigNetworkScore for " + config.configKey()
129881c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                        + " isActive=" + isActive
1299e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " score = " + Integer.toString(startScore));
1300e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
1301e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle        }
1302e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle
13031db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        return startScore;
13042451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
13052451dbcc4f9641df188326215b204b798eb70c46vandwalle
13062451dbcc4f9641df188326215b204b798eb70c46vandwalle    /**
13078639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson     * Set whether connections to untrusted connections are allowed.
13088639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson     */
13098639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    void setAllowUntrustedConnections(boolean allow) {
13108639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        boolean changed = mAllowUntrustedConnections != allow;
13118639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        mAllowUntrustedConnections = allow;
13128639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        if (changed) {
1313005c1ef113192f898499a407dd266393a8d6b076vandwalle            // Trigger a scan so as to reattempt autojoin
1314005c1ef113192f898499a407dd266393a8d6b076vandwalle            mWifiStateMachine.startScanForUntrustedSettingChange();
13158639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        }
13168639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    }
13178639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
13188639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    private boolean isOpenNetwork(ScanResult result) {
13198639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        return !result.capabilities.contains("WEP") &&
13208639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                !result.capabilities.contains("PSK") &&
13218639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                !result.capabilities.contains("EAP");
13228639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    }
13238639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
132416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson    private boolean haveRecentlySeenScoredBssid(WifiConfiguration config) {
132516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        long ephemeralOutOfRangeTimeoutMs = Settings.Global.getLong(
132616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                mContext.getContentResolver(),
132716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                Settings.Global.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS,
132816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                DEFAULT_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS);
132916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
133016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // Check whether the currently selected network has a score curve. If
133116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // ephemeralOutOfRangeTimeoutMs is <= 0, then this is all we check, and we stop here.
133216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // Otherwise, we stop here if the currently selected network has a score. If it doesn't, we
133316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // keep going - it could be that another BSSID is in range (has been seen recently) which
133416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // has a score, even if the one we're immediately connected to doesn't.
133516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        ScanResult currentScanResult =  mWifiStateMachine.getCurrentScanResult();
133616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        boolean currentNetworkHasScoreCurve = mNetworkScoreCache.hasScoreCurve(currentScanResult);
133716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        if (ephemeralOutOfRangeTimeoutMs <= 0 || currentNetworkHasScoreCurve) {
133816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            if (DBG) {
133916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                if (currentNetworkHasScoreCurve) {
134016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    logDbg("Current network has a score curve, keeping network: "
134116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                            + currentScanResult);
134216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                } else {
134316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    logDbg("Current network has no score curve, giving up: " + config.SSID);
134416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                }
134516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            }
134616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            return currentNetworkHasScoreCurve;
134716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        }
134816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
134916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        if (config.scanResultCache == null || config.scanResultCache.isEmpty()) {
135016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            return false;
135116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        }
135216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
135316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        long currentTimeMs = System.currentTimeMillis();
135416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        for (ScanResult result : config.scanResultCache.values()) {
135516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            if (currentTimeMs > result.seen
135616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    && currentTimeMs - result.seen < ephemeralOutOfRangeTimeoutMs
135716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    && mNetworkScoreCache.hasScoreCurve(result)) {
135816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                if (DBG) {
135916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    logDbg("Found scored BSSID, keeping network: " + result.BSSID);
136016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                }
136116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                return true;
136216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            }
136316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        }
136416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
136516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        if (DBG) {
136616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            logDbg("No recently scored BSSID found, giving up connection: " + config.SSID);
136716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        }
136816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        return false;
136916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson    }
137016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
137177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // After WifiStateMachine ask the supplicant to associate or reconnect
137277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // we might still obtain scan results from supplicant
137377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // however the supplicant state in the mWifiInfo and supplicant state tracker
137477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // are updated when we get the supplicant state change message which can be
137577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // processed after the SCAN_RESULT message, so at this point the framework doesn't
137677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // know that supplicant is ASSOCIATING.
137777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // A good fix for this race condition would be for the WifiStateMachine to add
137877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // a new transient state where it expects to get the supplicant message indicating
137977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // that it started the association process and within which critical operations
138077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // like autojoin should be deleted.
138177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
138277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // This transient state would remove the need for the roam Wathchdog which
138377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // basically does that.
138477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
138577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // At the moment, we just query the supplicant state synchronously with the
138677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // mWifiNative.status() command, which allow us to know that
138777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // supplicant has started association process, even though we didnt yet get the
138877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // SUPPLICANT_STATE_CHANGE message.
138977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
139077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final List<String> ASSOC_STATES = Arrays.asList(
139177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "ASSOCIATING",
139277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "ASSOCIATED",
139377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "FOUR_WAY_HANDSHAKE",
139477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "GROUP_KEY_HANDSHAKE");
139577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
139677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private int getNetID(String wpaStatus) {
139777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (VDBG) {
139877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            logDbg("attemptAutoJoin() status=" + wpaStatus);
139977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
140077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
140177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        try {
140277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            int id = WifiConfiguration.INVALID_NETWORK_ID;
140377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            String state = null;
140477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            BufferedReader br = new BufferedReader(new StringReader(wpaStatus));
140577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            String line;
140677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            while((line = br.readLine()) != null) {
140777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                int split = line.indexOf('=');
140877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                if (split < 0) {
140977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    continue;
141077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                }
141177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
141277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                String name = line.substring(0, split);
141377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                if (name.equals("id")) {
141477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    try {
141577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        id = Integer.parseInt(line.substring(split+1));
141677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        if (state != null) {
141777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                            break;
141877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        }
141977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    }
142077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    catch (NumberFormatException nfe) {
142177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        Log.d("HS2J", "NFE on '" + line + "'");
142277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        return WifiConfiguration.INVALID_NETWORK_ID;
142377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    }
142477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                }
142577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                else if (name.equals("wpa_state")) {
142677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    state = line.substring(split+1);
142777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    Log.d("HS2J", "State: '" + line + "'");
142877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    if (ASSOC_STATES.contains(state)) {
142977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        return WifiConfiguration.INVALID_NETWORK_ID;
143077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    }
143177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    else if (id >= 0) {
143277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        break;
143377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    }
143477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                }
143577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
143677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return id;
143777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
143877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        catch (IOException ioe) {
143977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return WifiConfiguration.INVALID_NETWORK_ID;    // Won't happen
144077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
144177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
144277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
144377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private boolean setCurrentConfigurationKey(WifiConfiguration currentConfig,
144477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                                               int supplicantNetId) {
144577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (currentConfig != null) {
144677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (supplicantNetId != currentConfig.networkId
144777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    // https://b.corp.google.com/issue?id=16484607
144877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    // mark this condition as an error only if the mismatched networkId are valid
144977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    && supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID
145077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    && currentConfig.networkId != WifiConfiguration.INVALID_NETWORK_ID) {
145177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                logDbg("attemptAutoJoin() ERROR wpa_supplicant out of sync nid="
145277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        + Integer.toString(supplicantNetId) + " WifiStateMachine="
145377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        + Integer.toString(currentConfig.networkId));
145477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mWifiStateMachine.disconnectCommand();
145577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                return false;
145677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            } else if (currentConfig.ephemeral && (!mAllowUntrustedConnections ||
145777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    !haveRecentlySeenScoredBssid(currentConfig))) {
145877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // The current connection is untrusted (the framework added it), but we're either
145977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // no longer allowed to connect to such networks, the score has been nullified
146077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // since we connected, or the scored BSSID has gone out of range.
146177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // Drop the current connection and perform the rest of autojoin.
146277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                logDbg("attemptAutoJoin() disconnecting from unwanted ephemeral network");
146377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mWifiStateMachine.disconnectCommand(Process.WIFI_UID,
146477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        mAllowUntrustedConnections ? 1 : 0);
146577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                return false;
146677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            } else {
146777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mCurrentConfigurationKey = currentConfig.configKey();
146877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                return true;
146977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
147077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        } else {
147177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            // If not invalid, then maybe in the process of associating, skip this attempt
147277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return supplicantNetId == WifiConfiguration.INVALID_NETWORK_ID;
147377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
147477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
147577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
147677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private void updateBlackListStatus(WifiConfiguration config, long now) {
147777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        // Wait for 5 minutes before reenabling config that have known,
147877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        // repeated connection or DHCP failures
147977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (config.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE
148077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                || config.disableReason
148177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                == WifiConfiguration.DISABLED_ASSOCIATION_REJECT
148277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                || config.disableReason
148377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                == WifiConfiguration.DISABLED_AUTH_FAILURE) {
148477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (config.blackListTimestamp == 0
148577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    || (config.blackListTimestamp > now)) {
148677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // Sanitize the timestamp
148777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.blackListTimestamp = now;
148877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
148977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if ((now - config.blackListTimestamp) >
149077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    mWifiConfigStore.wifiConfigBlacklistMinTimeMilli) {
149177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // Re-enable the WifiConfiguration
149277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.status = WifiConfiguration.Status.ENABLED;
149377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
149477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                // Reset the blacklist condition
149577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.numConnectionFailures = 0;
149677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.numIpConfigFailures = 0;
149777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.numAuthFailures = 0;
149877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
149977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
150077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                config.dirty = true;
150177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            } else {
150277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                if (VDBG) {
150377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    long delay = mWifiConfigStore.wifiConfigBlacklistMinTimeMilli
150477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                            - (now - config.blackListTimestamp);
150577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    logDbg("attemptautoJoin " + config.configKey()
150677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                            + " dont unblacklist yet, waiting for "
150777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                            + delay + " ms");
150877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                }
150977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
151077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
151177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        // Avoid networks disabled because of AUTH failure altogether
151277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (DBG) {
151377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            logDbg("attemptAutoJoin skip candidate due to auto join status "
151477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    + Integer.toString(config.autoJoinStatus) + " key "
151577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    + config.configKey(true)
151677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    + " reason " + config.disableReason);
151777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
151877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
151977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
152077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    boolean underSoftThreshold(WifiConfiguration config) {
152177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return config.visibility.rssi24 < mWifiConfigStore.thresholdUnblacklistThreshold24Soft.get()
152277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            && config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Soft.get();
152377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
152477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
152577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    boolean underHardThreshold(WifiConfiguration config) {
152677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return config.visibility.rssi24 < mWifiConfigStore.thresholdUnblacklistThreshold24Hard.get()
152777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            && config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Hard.get();
152877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
152977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
153077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    boolean underThreshold(WifiConfiguration config, int rssi24, int rssi5) {
153177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return config.visibility.rssi24 < rssi24 && config.visibility.rssi5 < rssi5;
153277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
153377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
15348639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    /**
1535931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * attemptAutoJoin() function implements the core of the a network switching algorithm
153668fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle     * Return false if no acceptable networks were found.
1537931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
153868fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle    boolean attemptAutoJoin() {
153968fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle        boolean found = false;
1540c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        didOverride = false;
15411ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        didBailDueToWeakRssi = false;
1542b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        int networkSwitchType = AUTO_JOIN_IDLE;
15434dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
15448242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle        long now = System.currentTimeMillis();
15458242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle
15468c9088d11880553458f09377cc60d6eb7e66747bvandwalle        String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
15478c9088d11880553458f09377cc60d6eb7e66747bvandwalle
1548931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Reset the currentConfiguration Key, and set it only if WifiStateMachine and
1549453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        // supplicant agree
1550453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        mCurrentConfigurationKey = null;
1551453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        WifiConfiguration currentConfiguration = mWifiStateMachine.getCurrentWifiConfiguration();
1552453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
1553f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration candidate = null;
1554f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1555931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Obtain the subset of recently seen networks
1556833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        List<WifiConfiguration> list =
1557833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                mWifiConfigStore.getRecentConfiguredNetworks(mScanResultAutoJoinAge, false);
1558f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (list == null) {
15592f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            if (VDBG)  logDbg("attemptAutoJoin nothing known=" +
15602f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    mWifiConfigStore.getconfiguredNetworkSize());
156168fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle            return false;
1562f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1563f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1564931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Find the currently connected network: ask the supplicant directly
156577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
156677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        int supplicantNetId = getNetID(mWifiNative.status(true));
156777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1568ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (DBG) {
15697806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            String conf = "";
1570b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String last = "";
15717806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentConfiguration != null) {
1572e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                conf = " current=" + currentConfiguration.configKey();
1573b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1574b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (lastSelectedConfiguration != null) {
15752f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                last = " last=" + lastSelectedConfiguration;
15767806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            }
1577ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            logDbg("attemptAutoJoin() num recent config " + Integer.toString(list.size())
1578b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + conf + last
1579b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + " ---> suppNetId=" + Integer.toString(supplicantNetId));
1580ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
1581f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
158277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (!setCurrentConfigurationKey(currentConfiguration, supplicantNetId)) {
158377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return false;
1584453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        }
1585453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
1586b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        int currentNetId = -1;
1587b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentConfiguration != null) {
1588931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // If we are associated to a configuration, it will
1589b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            // be compared thru the compareNetwork function
1590b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            currentNetId = currentConfiguration.networkId;
1591b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
1592b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle
1593931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1594931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * Run thru all visible configurations without looking at the one we
1595c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle         * are currently associated to
15964dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle         * select Best Network candidate from known WifiConfigurations
1597931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1598f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (WifiConfiguration config : list) {
1599e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            if (config.SSID == null) {
1600b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                continue;
1601e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            }
1602e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
160377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (config.autoJoinStatus >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
160477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                updateBlackListStatus(config, now);
1605f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1606f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1607f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1608931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to un-blacklist based on elapsed time
160927355a942653264388e909a4276196ee63e57811vandwalle            if (config.blackListTimestamp > 0) {
161027355a942653264388e909a4276196ee63e57811vandwalle                if (now < config.blackListTimestamp) {
1611931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    /**
1612931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * looks like there was a change in the system clock since we black listed, and
1613931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * timestamp is not meaningful anymore, hence lose it.
1614931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * this event should be rare enough so that we still want to lose the black list
16152451dbcc4f9641df188326215b204b798eb70c46vandwalle                     */
161627355a942653264388e909a4276196ee63e57811vandwalle                    config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
161727355a942653264388e909a4276196ee63e57811vandwalle                } else {
16184dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    if ((now - config.blackListTimestamp) > loseBlackListHardMilli) {
1619931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Reenable it after 18 hours, i.e. next day
162027355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
16214dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    } else if ((now - config.blackListTimestamp) > loseBlackListSoftMilli) {
1622931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Lose blacklisting due to bad link
162327355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(config.autoJoinStatus - 8);
162427355a942653264388e909a4276196ee63e57811vandwalle                    }
162527355a942653264388e909a4276196ee63e57811vandwalle                }
162627355a942653264388e909a4276196ee63e57811vandwalle            }
162727355a942653264388e909a4276196ee63e57811vandwalle
162877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            // !!! JNo: This ought to be checked here rather than below...
162977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (config.visibility == null) {
163077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                continue;
163177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
163277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1633931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to unblacklist based on good visibility
163477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (underSoftThreshold(config)) {
163577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                logDenial("attemptAutoJoin do not unblacklist due to low visibility ", config);
163677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            } else if (underHardThreshold(config)) {
1637931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // If the network is simply temporary disabled, don't allow reconnect until
1638931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // RSSI becomes good enough
163927355a942653264388e909a4276196ee63e57811vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 1);
164077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                logDenial("attemptAutoJoin good candidate seen, bumped soft -> status=", config);
164127355a942653264388e909a4276196ee63e57811vandwalle            } else {
1642c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 3);
164377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                logDenial("attemptAutoJoin good candidate seen, bumped hard -> status=", config);
164427355a942653264388e909a4276196ee63e57811vandwalle            }
164527355a942653264388e909a4276196ee63e57811vandwalle
164627355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
164727355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED) {
1648931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Network is blacklisted, skip
164977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                logDenial("attemptAutoJoin skip blacklisted -> status=", config);
165027355a942653264388e909a4276196ee63e57811vandwalle                continue;
165127355a942653264388e909a4276196ee63e57811vandwalle            }
1652f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (config.networkId == currentNetId) {
1653ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
165421bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    logDbg("attemptAutoJoin skip current candidate  "
165521bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                            + Integer.toString(currentNetId)
1656ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + " key " + config.configKey(true));
1657ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
1658f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1659f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1660f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
16610eebae7334d6129f7ca1344e4b20199794994358vandwalle            boolean isLastSelected = false;
16620eebae7334d6129f7ca1344e4b20199794994358vandwalle            if (lastSelectedConfiguration != null &&
16630eebae7334d6129f7ca1344e4b20199794994358vandwalle                    config.configKey().equals(lastSelectedConfiguration)) {
16640eebae7334d6129f7ca1344e4b20199794994358vandwalle                isLastSelected = true;
16650eebae7334d6129f7ca1344e4b20199794994358vandwalle            }
16660eebae7334d6129f7ca1344e4b20199794994358vandwalle
16671ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            int boost = config.autoJoinUseAggressiveJoinAttemptThreshold + weakRssiBailCount;
166877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (underThreshold(config,
166977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    mWifiConfigStore.thresholdInitialAutoJoinAttemptMin24RSSI.get() - boost,
167077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    mWifiConfigStore.thresholdInitialAutoJoinAttemptMin5RSSI.get() - boost)) {
167177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
167277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                logDenial("attemptAutoJoin skip due to low visibility -> status=", config);
16730eebae7334d6129f7ca1344e4b20199794994358vandwalle
1674c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // Don't try to autojoin a network that is too far but
1675c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // If that configuration is a user's choice however, try anyway
16760eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (!isLastSelected) {
16770eebae7334d6129f7ca1344e4b20199794994358vandwalle                    config.autoJoinBailedDueToLowRssi = true;
16781ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                    didBailDueToWeakRssi = true;
16798c9088d11880553458f09377cc60d6eb7e66747bvandwalle                    continue;
16800eebae7334d6129f7ca1344e4b20199794994358vandwalle                } else {
16810eebae7334d6129f7ca1344e4b20199794994358vandwalle                    // Next time, try to be a bit more aggressive in auto-joining
16820eebae7334d6129f7ca1344e4b20199794994358vandwalle                    if (config.autoJoinUseAggressiveJoinAttemptThreshold
1683dd0c558776fcfba3f754bb0cd6533f2c9c23ec1evandwalle                            < WifiConfiguration.MAX_INITIAL_AUTO_JOIN_RSSI_BOOST
1684dd0c558776fcfba3f754bb0cd6533f2c9c23ec1evandwalle                            && config.autoJoinBailedDueToLowRssi) {
1685dd0c558776fcfba3f754bb0cd6533f2c9c23ec1evandwalle                        config.autoJoinUseAggressiveJoinAttemptThreshold += 4;
16864dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    }
16878c9088d11880553458f09377cc60d6eb7e66747bvandwalle                }
16880eebae7334d6129f7ca1344e4b20199794994358vandwalle            }
1689d30127db46224e45554f8964209221bba8ad41d9vandwalle            if (config.numNoInternetAccessReports > 0
1690d30127db46224e45554f8964209221bba8ad41d9vandwalle                    && !isLastSelected
1691d30127db46224e45554f8964209221bba8ad41d9vandwalle                    && !config.validatedInternetAccess) {
1692d30127db46224e45554f8964209221bba8ad41d9vandwalle                // Avoid autoJoining this network because last time we used it, it didn't
1693d30127db46224e45554f8964209221bba8ad41d9vandwalle                // have internet access, and we never manage to validate internet access on this
1694d30127db46224e45554f8964209221bba8ad41d9vandwalle                // network configuration
16950eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (DBG) {
1696d30127db46224e45554f8964209221bba8ad41d9vandwalle                    logDbg("attemptAutoJoin skip candidate due to no InternetAccess  "
1697d30127db46224e45554f8964209221bba8ad41d9vandwalle                            + config.configKey(true)
1698d30127db46224e45554f8964209221bba8ad41d9vandwalle                            + " num reports " + config.numNoInternetAccessReports);
16999f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                }
17000eebae7334d6129f7ca1344e4b20199794994358vandwalle                continue;
17018c9088d11880553458f09377cc60d6eb7e66747bvandwalle            }
17028c9088d11880553458f09377cc60d6eb7e66747bvandwalle
1703ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            if (DBG) {
1704e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                String cur = "";
1705e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                if (candidate != null) {
1706e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    cur = " current candidate " + candidate.configKey();
1707e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                }
1708e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("attemptAutoJoin trying id="
1709c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + Integer.toString(config.networkId) + " "
1710b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                        + config.configKey(true)
1711e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " status=" + config.autoJoinStatus
1712e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + cur);
1713ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            }
1714f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1715f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate == null) {
1716f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                candidate = config;
1717f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
1718f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)  {
1719453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("attemptAutoJoin will compare candidate  " + candidate.configKey()
17204dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " with " + config.configKey());
1721f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1722833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                int order = compareWifiConfigurations(candidate, config);
17232451dbcc4f9641df188326215b204b798eb70c46vandwalle
17242451dbcc4f9641df188326215b204b798eb70c46vandwalle                // The lastSelectedConfiguration is the configuration the user has manually selected
1725c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // thru WifiPicker, or that a 3rd party app asked us to connect to via the
17262451dbcc4f9641df188326215b204b798eb70c46vandwalle                // enableNetwork with disableOthers=true WifiManager API
17272451dbcc4f9641df188326215b204b798eb70c46vandwalle                // As this is a direct user choice, we strongly prefer this configuration,
17282451dbcc4f9641df188326215b204b798eb70c46vandwalle                // hence give +/-100
17292451dbcc4f9641df188326215b204b798eb70c46vandwalle                if ((lastSelectedConfiguration != null)
17302451dbcc4f9641df188326215b204b798eb70c46vandwalle                        && candidate.configKey().equals(lastSelectedConfiguration)) {
17312451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // candidate is the last selected configuration,
17322451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // so keep it above connect choices (+/-60) and
17332451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // above RSSI/scorer based selection of linked configuration (+/- 50)
17342451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // by reducing order by -100
17352451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = order - 100;
17362451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (VDBG)   {
17372f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        logDbg("     ...and prefers -100 " + candidate.configKey()
17382451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " over " + config.configKey()
17392451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " because it is the last selected -> "
17402451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + Integer.toString(order));
17412451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
17422451dbcc4f9641df188326215b204b798eb70c46vandwalle                } else if ((lastSelectedConfiguration != null)
17432451dbcc4f9641df188326215b204b798eb70c46vandwalle                        && config.configKey().equals(lastSelectedConfiguration)) {
17442451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // config is the last selected configuration,
17452451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // so keep it above connect choices (+/-60) and
17462451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // above RSSI/scorer based selection of linked configuration (+/- 50)
17472451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // by increasing order by +100
17482451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = order + 100;
17492451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (VDBG)   {
17502f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        logDbg("     ...and prefers +100 " + config.configKey()
17512451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " over " + candidate.configKey()
17522451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " because it is the last selected -> "
17532451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + Integer.toString(order));
17542451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
17552451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
17562451dbcc4f9641df188326215b204b798eb70c46vandwalle
1757f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (order > 0) {
1758931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Ascending : candidate < config
1759f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    candidate = config;
1760f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1761f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1762f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1763f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
17642451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Now, go thru scan result to try finding a better untrusted network
1765833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        if (mNetworkScoreCache != null && mAllowUntrustedConnections) {
1766f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi5 = WifiConfiguration.INVALID_RSSI;
1767f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi24 = WifiConfiguration.INVALID_RSSI;
1768f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate != null) {
1769f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi5 = candidate.visibility.rssi5;
1770f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi24 = candidate.visibility.rssi24;
1771f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1772f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1773931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Get current date
17742451dbcc4f9641df188326215b204b798eb70c46vandwalle            long nowMs = System.currentTimeMillis();
1775c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            int currentScore = -10000;
1776c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // The untrusted network with highest score
1777c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            ScanResult untrustedCandidate = null;
17782451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Look for untrusted scored network only if the current candidate is bad
1779c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (isBadCandidate(rssi24, rssi5)) {
1780f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                for (ScanResult result : scanResultCache.values()) {
1781c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // We look only at untrusted networks with a valid SSID
1782c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // A trusted result would have been looked at thru it's Wificonfiguration
17838639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                    if (TextUtils.isEmpty(result.SSID) || !result.untrusted ||
17848639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                            !isOpenNetwork(result)) {
1785c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        continue;
1786c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    }
17872ce99b40c36ed0352b31aa85d5f9383d5f0506f5vandwalle                    if (mWifiConfigStore.mDeletedEphemeralSSIDs.contains
17882ce99b40c36ed0352b31aa85d5f9383d5f0506f5vandwalle                            ("\"" + result.SSID + "\"")) {
17892ce99b40c36ed0352b31aa85d5f9383d5f0506f5vandwalle                        // SSID had been Forgotten by user, then don't score it
17902ce99b40c36ed0352b31aa85d5f9383d5f0506f5vandwalle                        continue;
17912ce99b40c36ed0352b31aa85d5f9383d5f0506f5vandwalle                    }
1792833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                    if ((nowMs - result.seen) < mScanResultAutoJoinAge) {
1793c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        // Increment usage count for the network
1794c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        mWifiConnectionStatistics.incrementOrAddUntrusted(result.SSID, 0, 1);
1795c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
179681c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                        boolean isActiveNetwork = lastUntrustedBSSID != null
179781c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                                && result.BSSID.equals(lastUntrustedBSSID);
179881c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                        int score = mNetworkScoreCache.getNetworkScore(result, isActiveNetwork);
1799c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        if (score != WifiNetworkScoreCache.INVALID_NETWORK_SCORE
1800c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                && score > currentScore) {
1801c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            // Highest score: Select this candidate
1802c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            currentScore = score;
1803c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            untrustedCandidate = result;
1804c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            if (VDBG) {
1805c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                logDbg("AutoJoinController: found untrusted candidate "
1806c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                        + result.SSID
1807c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                + " RSSI=" + result.level
1808c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                + " freq=" + result.frequency
1809c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                + " score=" + score);
1810c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            }
1811f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        }
1812f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
1813f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1814f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1815c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (untrustedCandidate != null) {
1816c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                if (lastUntrustedBSSID == null
1817c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        || !untrustedCandidate.SSID.equals(lastUntrustedBSSID)) {
1818c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // We found a new candidate that we are going to connect to, then
1819c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // increase its connection count
18208c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    mWifiConnectionStatistics.
18218c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                            incrementOrAddUntrusted(untrustedCandidate.SSID, 1, 0);
1822c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // Remember which SSID we are connecting to
1823c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    lastUntrustedBSSID = untrustedCandidate.SSID;
1824c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                }
18258639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
18268639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                // At this point, we have an untrusted network candidate.
18278639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                // Create the new ephemeral configuration and see if we should switch over
1828833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                candidate =
1829833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                        mWifiConfigStore.wifiConfigurationFromScanResult(untrustedCandidate);
1830833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                candidate.allowedKeyManagement.set(KeyMgmt.NONE);
1831833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                candidate.ephemeral = true;
1832c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            }
1833c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        }
1834b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
18351ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        long lastUnwanted =
18361ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                System.currentTimeMillis()
18371ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                        - mWifiConfigStore.lastUnwantedNetworkDisconnectTimestamp;
18381ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        if (candidate == null
18391ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && lastSelectedConfiguration == null
18401ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && currentConfiguration == null
18411ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && didBailDueToWeakRssi
18421ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && (mWifiConfigStore.lastUnwantedNetworkDisconnectTimestamp == 0
18431ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                    || lastUnwanted > (1000 * 60 * 60 * 24 * 7))
18441ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                ) {
18451ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // We are bailing out of autojoin although we are seeing a weak configuration, and
18461ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - we didn't find another valid candidate
18471ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - we are not connected
18481ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - without a user network selection choice
18491ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - ConnectivityService has not triggered an unwanted network disconnect
18501ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            //       on this device for a week (hence most likely there is no SIM card or cellular)
18511ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // If all those conditions are met, then boost the RSSI of the weak networks
18521ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // that we are seeing so as we will eventually pick one
18531ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            if (weakRssiBailCount < 10)
18541ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                weakRssiBailCount += 1;
18551ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        } else {
18561ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            if (weakRssiBailCount > 0)
18571ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                weakRssiBailCount -= 1;
18581ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        }
18591ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle
1860931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1861931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         *  If candidate is found, check the state of the connection so as
1862931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         *  to decide if we should be acting on this candidate and switching over
1863931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1864e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        int networkDelta = compareNetwork(candidate, lastSelectedConfiguration);
1865b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (DBG && candidate != null) {
1866b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String doSwitch = "";
1867b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String current = "";
1868b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (networkDelta < 0) {
1869b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                doSwitch = " -> not switching";
1870b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1871b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (currentConfiguration != null) {
18722f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                current = " with current " + currentConfiguration.configKey();
1873b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1874b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("attemptAutoJoin networkSwitching candidate "
1875b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                    + candidate.configKey()
1876b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + current
1877c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    + " linked=" + (currentConfiguration != null
1878b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            && currentConfiguration.isLinked(candidate))
1879b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + " : delta="
1880b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + Integer.toString(networkDelta) + " "
1881b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + doSwitch);
1882b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
18834dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1884931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1885931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * Ask WifiStateMachine permission to switch :
1886931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * if user is currently streaming voice traffic,
1887931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * then we should not be allowed to switch regardless of the delta
1888931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
188977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (mWifiStateMachine.shouldSwitchNetwork(networkDelta)) {      // !!! JNo: Here!
1890b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (mStaStaSupported) {
1891b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("mStaStaSupported --> error do nothing now ");
1892b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            } else {
1893b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (currentConfiguration != null && currentConfiguration.isLinked(candidate)) {
1894b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_EXTENDED_ROAMING;
1895b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                } else {
1896b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_OUT_OF_NETWORK_ROAMING;
1897b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1898b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1899b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto connect with netId "
1900b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(candidate.networkId)
1901b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " to " + candidate.configKey());
1902b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
19032451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (didOverride) {
19042451dbcc4f9641df188326215b204b798eb70c46vandwalle                    candidate.numScorerOverrideAndSwitchedNetwork++;
19052451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
1906c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                candidate.numAssociation++;
1907e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                mWifiConnectionStatistics.numAutoJoinAttempt++;
19089f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
19092f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                if (candidate.BSSID == null || candidate.BSSID.equals("any")) {
19102f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // First step we selected the configuration we want to connect to
19112f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // Second step: Look for the best Scan result for this configuration
19122f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // TODO this algorithm should really be done in one step
19132f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    String currentBSSID = mWifiStateMachine.getCurrentBSSID();
1914833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                    ScanResult roamCandidate =
1915833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                            attemptRoam(null, candidate, mScanResultAutoJoinAge, null);
19162f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    if (roamCandidate != null && currentBSSID != null
19172f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                            && currentBSSID.equals(roamCandidate.BSSID)) {
19182f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // Sanity, we were already asociated to that candidate
19192f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        roamCandidate = null;
19202f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    }
19212f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    if (roamCandidate != null && roamCandidate.is5GHz()) {
19222f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // If the configuration hasn't a default BSSID selected, and the best
19232f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // candidate is 5GHZ, then select this candidate so as WifiStateMachine and
19242f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // supplicant will pick it first
19252f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        candidate.autoJoinBSSID = roamCandidate.BSSID;
19262f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        if (VDBG) {
19272f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                            logDbg("AutoJoinController: lock to 5GHz "
19282f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                                    + candidate.autoJoinBSSID
19292f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                                    + " RSSI=" + roamCandidate.level
19302f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                                    + " freq=" + roamCandidate.frequency);
19312f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        }
1932448c9536a302c58a79e271b1721c08b8882f800evandwalle                    } else {
1933448c9536a302c58a79e271b1721c08b8882f800evandwalle                        // We couldnt find a roam candidate
1934448c9536a302c58a79e271b1721c08b8882f800evandwalle                        candidate.autoJoinBSSID = "any";
19359f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    }
19369f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                }
1937448c9536a302c58a79e271b1721c08b8882f800evandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT,
1938448c9536a302c58a79e271b1721c08b8882f800evandwalle                            candidate.networkId, networkSwitchType, candidate);
193968fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                found = true;
19404dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
1941b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
19424dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1943b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (networkSwitchType == AUTO_JOIN_IDLE) {
1944e67ec726c07410073575473c0f50dc737629f5davandwalle            String currentBSSID = mWifiStateMachine.getCurrentBSSID();
1945931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Attempt same WifiConfiguration roaming
1946833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle            ScanResult roamCandidate =
1947833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                    attemptRoam(null, currentConfiguration, mScanResultAutoJoinAge, currentBSSID);
1948e67ec726c07410073575473c0f50dc737629f5davandwalle            /**
1949e67ec726c07410073575473c0f50dc737629f5davandwalle             *  TODO: (post L initial release)
1950e67ec726c07410073575473c0f50dc737629f5davandwalle             *  consider handling linked configurations roaming (i.e. extended Roaming)
1951e67ec726c07410073575473c0f50dc737629f5davandwalle             *  thru the attemptRoam function which makes use of the RSSI roaming threshold.
1952e67ec726c07410073575473c0f50dc737629f5davandwalle             *  At the moment, extended roaming is only handled thru the attemptAutoJoin()
1953e67ec726c07410073575473c0f50dc737629f5davandwalle             *  function which compare configurations.
1954e67ec726c07410073575473c0f50dc737629f5davandwalle             *
1955e67ec726c07410073575473c0f50dc737629f5davandwalle             *  The advantage of making use of attemptRoam function is that this function
1956e67ec726c07410073575473c0f50dc737629f5davandwalle             *  will looks at all the BSSID of each configurations, instead of only looking
1957e67ec726c07410073575473c0f50dc737629f5davandwalle             *  at WifiConfiguration.visibility which keeps trackonly of the RSSI/band of the
1958e67ec726c07410073575473c0f50dc737629f5davandwalle             *  two highest BSSIDs.
1959e67ec726c07410073575473c0f50dc737629f5davandwalle             */
1960e67ec726c07410073575473c0f50dc737629f5davandwalle            // Attempt linked WifiConfiguration roaming
1961e67ec726c07410073575473c0f50dc737629f5davandwalle            /* if (currentConfiguration != null
1962e67ec726c07410073575473c0f50dc737629f5davandwalle                    && currentConfiguration.linkedConfigurations != null) {
1963e67ec726c07410073575473c0f50dc737629f5davandwalle                for (String key : currentConfiguration.linkedConfigurations.keySet()) {
1964e67ec726c07410073575473c0f50dc737629f5davandwalle                    WifiConfiguration link = mWifiConfigStore.getWifiConfiguration(key);
1965e67ec726c07410073575473c0f50dc737629f5davandwalle                    if (link != null) {
1966833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                        roamCandidate = attemptRoam(roamCandidate, link, mScanResultAutoJoinAge,
1967e67ec726c07410073575473c0f50dc737629f5davandwalle                                currentBSSID);
1968e67ec726c07410073575473c0f50dc737629f5davandwalle                    }
1969e67ec726c07410073575473c0f50dc737629f5davandwalle                }
1970e67ec726c07410073575473c0f50dc737629f5davandwalle            }*/
1971e67ec726c07410073575473c0f50dc737629f5davandwalle            if (roamCandidate != null && currentBSSID != null
1972e67ec726c07410073575473c0f50dc737629f5davandwalle                    && currentBSSID.equals(roamCandidate.BSSID)) {
1973e67ec726c07410073575473c0f50dc737629f5davandwalle                roamCandidate = null;
1974e67ec726c07410073575473c0f50dc737629f5davandwalle            }
19752f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            if (roamCandidate != null && mWifiStateMachine.shouldSwitchNetwork(999)) {
1976b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1977b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto roam with netId "
1978b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(currentConfiguration.networkId)
1979b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " " + currentConfiguration.configKey() + " to BSSID="
1980b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + roamCandidate.BSSID + " freq=" + roamCandidate.frequency
19811ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                            + " RSSI=" + roamCandidate.level);
1982b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1983b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                networkSwitchType = AUTO_JOIN_ROAMING;
1984e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                mWifiConnectionStatistics.numAutoRoamAttempt++;
1985e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle
1986b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_ROAM,
1987b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                            currentConfiguration.networkId, 1, roamCandidate);
198868fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                found = true;
1989f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1990f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1991b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (VDBG) logDbg("Done attemptAutoJoin status=" + Integer.toString(networkSwitchType));
199268fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle        return found;
1993f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
199477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
199577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private void logDenial(String reason, WifiConfiguration config) {
199677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (!DBG) {
199777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return;
199877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
199977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        logDbg(reason + config.toString());
200077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
2001f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle}
2002f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
2003