WifiAutoJoinController.java revision 3a2a3d226881cce8a4e511302231d843b0def303
1f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle/*
262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle * Copyright (C) 2014 The Android Open Source Project
3f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
4f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * Licensed under the Apache License, Version 2.0 (the "License");
5f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * you may not use this file except in compliance with the License.
6f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * You may obtain a copy of the License at
7f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
8f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *      http://www.apache.org/licenses/LICENSE-2.0
9f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
10f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * Unless required by applicable law or agreed to in writing, software
11f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * distributed under the License is distributed on an "AS IS" BASIS,
12f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * See the License for the specific language governing permissions and
14f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * limitations under the License.
15f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle */
16f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
17f22d23092ab37286a5ef9d257d5bb32c421d2669vandwallepackage com.android.server.wifi;
18f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
19f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.content.Context;
20f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
21f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.NetworkKey;
22f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.NetworkScoreManager;
230c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport android.net.WifiKey;
24f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.wifi.WifiConfiguration;
25f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.wifi.ScanResult;
26f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.wifi.WifiManager;
27f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
28f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.os.SystemClock;
29b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalleimport android.os.Process;
30f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.util.Log;
31f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
320c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport java.util.ArrayList;
330c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport java.util.Collection;
34f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.Iterator;
35f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.HashMap;
36f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.List;
37f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.Date;
38f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
39f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle/**
40f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * AutoJoin controller is responsible for WiFi Connect decision
41f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
42f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * It runs in the thread context of WifiStateMachine
43f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
44f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle */
45f22d23092ab37286a5ef9d257d5bb32c421d2669vandwallepublic class WifiAutoJoinController {
46f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
47f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private Context mContext;
48f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiStateMachine mWifiStateMachine;
49f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiConfigStore mWifiConfigStore;
50f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiTrafficPoller mWifiTrafficPoller;
51f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNative mWifiNative;
52f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
53f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private NetworkScoreManager scoreManager;
54f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNetworkScoreCache mNetworkScoreCache;
55f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
56f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final String TAG = "WifiAutoJoinController ";
57ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean DBG = false;
58ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean VDBG = false;
59f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final boolean mStaStaSupported = false;
60f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final int SCAN_RESULT_CACHE_SIZE = 80;
61f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
62453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle    private String mCurrentConfigurationKey = null; //used by autojoin
63f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
64f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private HashMap<String, ScanResult> scanResultCache =
65f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            new HashMap<String, ScanResult>();
66f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
6727355a942653264388e909a4276196ee63e57811vandwalle    //lose the non-auth failure blacklisting after 8 hours
684dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListHardMilli = 1000 * 60 * 60 * 8;
6927355a942653264388e909a4276196ee63e57811vandwalle    //lose some temporary blacklisting after 30 minutes
704dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListSoftMilli = 1000 * 60 * 30;
7127355a942653264388e909a4276196ee63e57811vandwalle
72b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_IDLE = 0;
73b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_ROAMING = 1;
74b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_EXTENDED_ROAMING = 2;
75b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_OUT_OF_NETWORK_ROAMING = 3;
76b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
77f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    WifiAutoJoinController(Context c, WifiStateMachine w, WifiConfigStore s,
78f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                           WifiTrafficPoller t, WifiNative n) {
79f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mContext = c;
80f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiStateMachine = w;
81f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore = s;
82f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiTrafficPoller = t;
83f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiNative = n;
84f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mNetworkScoreCache = null;
8521bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle        scoreManager =
8621bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                (NetworkScoreManager) mContext.getSystemService(Context.NETWORK_SCORE_SERVICE);
87f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager == null)
88f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("Registered scoreManager NULL " + " service " + Context.NETWORK_SCORE_SERVICE);
89f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
90f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager != null) {
91f13817203179f41620514718c8668ae7e418f8afJeff Davidson            mNetworkScoreCache = new WifiNetworkScoreCache(mContext);
92f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            scoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
93f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        } else {
94f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("No network score service: Couldnt register as a WiFi score Manager, type="
95f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(NetworkKey.TYPE_WIFI)
96f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + " service " + Context.NETWORK_SCORE_SERVICE);
97f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            mNetworkScoreCache = null;
98f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
99f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
100f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
101ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    void enableVerboseLogging(int verbose) {
102ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (verbose > 0 ) {
103abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = true;
104ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = true;
105ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        } else {
106abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = false;
107ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = false;
108ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
109ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    }
110ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle
11121bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle    int mScanResultMaximumAge = 30000; /* milliseconds unit */
112f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
113ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    /*
114ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * flush out scan results older than mScanResultMaximumAge
115ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     *
116ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * */
117f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private void ageScanResultsOut(int delay) {
118f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (delay <= 0) {
119f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            delay = mScanResultMaximumAge; //something sane
120f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
121b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        long milli = System.currentTimeMillis();
122f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
123f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("ageScanResultsOut delay " + Integer.valueOf(delay) + " size "
124f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.valueOf(scanResultCache.size()) + " now " + Long.valueOf(milli));
125f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
126f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
127f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        Iterator<HashMap.Entry<String,ScanResult>> iter = scanResultCache.entrySet().iterator();
128f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        while (iter.hasNext()) {
129f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            HashMap.Entry<String,ScanResult> entry = iter.next();
130f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult result = entry.getValue();
131f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
132f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((result.seen + delay) < milli) {
133f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                iter.remove();
134f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
135f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
136f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
137f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
138f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void addToScanCache(List<ScanResult> scanList) {
139f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration associatedConfig;
140f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1410c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        ArrayList<NetworkKey> unknownScanResults = new ArrayList<NetworkKey>();
1420c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
143f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for(ScanResult result: scanList) {
1441fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng            if (result.SSID == null) continue;
145f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            result.seen = System.currentTimeMillis();
146f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
147f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult sr = scanResultCache.get(result.BSSID);
148f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (sr != null) {
149f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                // if there was a previous cache result for this BSSID, average the RSSI values
150f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
151f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int previous_rssi = sr.level;
152f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                long previously_seen_milli = sr.seen;
153f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
154f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                /* average RSSI with previously seen instances of this scan result */
155f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int avg_rssi = result.level;
156f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
157f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if ((previously_seen_milli > 0)
158f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        && (previously_seen_milli < mScanResultMaximumAge/2)) {
159f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    /*
160f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    *
161f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    * previously_seen_milli = 0 => RSSI = 0.5 * previous_seen_rssi + 0.5 * new_rssi
162f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    *
163f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    * If previously_seen_milli is 15+ seconds old:
164f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    *      previously_seen_milli = 15000 => RSSI = new_rssi
165f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    *
166f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    */
167f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
168f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    double alpha = 0.5 - (double)previously_seen_milli
169f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            / (double)mScanResultMaximumAge;
170f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
171f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    avg_rssi = (int)((double)avg_rssi * (1-alpha) + (double)previous_rssi * alpha);
172f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
173f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                result.level = avg_rssi;
174f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
175f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                //remove the previous Scan Result
176f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                scanResultCache.remove(result.BSSID);
1770c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            } else {
1780c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                if (!mNetworkScoreCache.isScoredNetwork(result)) {
17921bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    WifiKey wkey;
18021bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    //TODO : find out how we can get there without a valid UTF-8 encoded SSID
18121bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    //TODO: which will cause WifiKey constructor to fail
18221bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    try {
18321bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        wkey = new WifiKey("\"" + result.SSID + "\"", result.BSSID);
18421bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    } catch (IllegalArgumentException e) {
18521bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        logDbg("AutoJoinController: received badly encoded SSID=[" + result.SSID +
18621bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                                "] ->skipping this network");
18721bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        wkey = null;
18821bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    }
18921bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    if (wkey != null) {
19021bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        NetworkKey nkey = new NetworkKey(wkey);
19121bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        //if we don't know this scan result then request a score to Herrevad
19221bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        unknownScanResults.add(nkey);
19321bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    }
1940c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                }
195f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
196f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
197f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            scanResultCache.put(result.BSSID, new ScanResult(result));
198f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
199f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //add this BSSID to the scanResultCache of the relevant WifiConfiguration
200f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            associatedConfig = mWifiConfigStore.updateSavedNetworkHistory(result);
201f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
2020c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            //try to associate this BSSID to an existing Saved WifiConfiguration
203f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (associatedConfig == null) {
204f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                associatedConfig = mWifiConfigStore.associateWithConfiguration(result);
2051fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng                if (associatedConfig != null && associatedConfig.SSID != null) {
206f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (VDBG) {
207f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        logDbg("addToScanCache save associated config "
208f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                + associatedConfig.SSID + " with " + associatedConfig.SSID);
209f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
210f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    mWifiStateMachine.sendMessage(WifiManager.SAVE_NETWORK, associatedConfig);
211f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
212f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
213f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
2140c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
2150c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        if (unknownScanResults.size() != 0) {
2160c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            NetworkKey[] newKeys =
2170c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                    unknownScanResults.toArray(new NetworkKey[unknownScanResults.size()]);
2180c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                //kick the score manager, we will get updated scores asynchronously
2190c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            scoreManager.requestScores(newKeys);
2200c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        }
221f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
222f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
223f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void logDbg(String message) {
2240888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle        logDbg(message, false);
225ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    }
226ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
227ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    void logDbg(String message, boolean stackTrace) {
228f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        long now = SystemClock.elapsedRealtimeNanos();
2290888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle        String ts = String.format("[%,d us] ", now / 1000);
230ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (stackTrace) {
231ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            Log.e(TAG, ts + message + " stack:"
232ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[2].getMethodName() + " - "
233ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[3].getMethodName() + " - "
234ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[4].getMethodName() + " - "
235ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[5].getMethodName());
236ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        } else {
237ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            Log.e(TAG, ts + message);
238ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        }
239f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
240f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
241f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    /* called directly from WifiStateMachine  */
242f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void newSupplicantResults() {
243f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        List<ScanResult> scanList = mWifiStateMachine.syncGetScanResultsList();
244f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        addToScanCache(scanList);
245f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(mScanResultMaximumAge);
246f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (DBG)
247f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle           logDbg("newSupplicantResults size=" + Integer.valueOf(scanResultCache.size()) );
248f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
249f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
250f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore.writeKnownNetworkHistory();
251f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
252f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
253f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
254f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
255f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    /* not used at the moment
256f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * should be a call back from WifiScanner HAL ??
257f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * this function is not hooked and working yet, it will receive scan results from WifiScanners
258f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * with the list of IEs,then populate the capabilities by parsing the IEs and inject the scan
259f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * results as normal.
260f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     */
261f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void newHalScanResults() {
262f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        List<ScanResult> scanList = null;//mWifiScanner.syncGetScanResultsList();
263f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String akm = WifiParser.parse_akm(null, null);
264f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        logDbg(akm);
265f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        addToScanCache(scanList);
266f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(0);
267f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
268f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore.writeKnownNetworkHistory();
269f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
270f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
271f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    /* network link quality changed, called directly from WifiTrafficPoller,
272f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    or by listening to Link Quality intent */
273f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void linkQualitySignificantChange() {
274f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
275f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
276f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
277f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    /*
278f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * compare a WifiConfiguration against the current network, return a delta score
279f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * If not associated, and the candidate will always be better
280f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * For instance if the candidate is a home network versus an unknown public wifi,
281f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * the delta will be infinite, else compare Kepler scores etc…
282b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * Negatve return values from this functions are meaningless per se, just trying to
283b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * keep them distinct for debug purpose (i.e. -1, -2 etc...)
284f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     ***/
285f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private int compareNetwork(WifiConfiguration candidate) {
286b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (candidate == null)
287b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -3;
288b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
289f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration currentNetwork = mWifiStateMachine.getCurrentWifiConfiguration();
290b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentNetwork == null) {
291b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle           return 1000;
292b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
293f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
294f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (candidate.configKey(true).equals(currentNetwork.configKey(true))) {
295b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -2;
296f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
297f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
298f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = compareWifiConfigurations(currentNetwork, candidate);
299f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
300f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order > 0) {
301f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //ascending: currentNetwork < candidate
302f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 10; //will try switch over to the candidate
303f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
304f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
305f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return 0;
306f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
307f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
308ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    /**
309ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * update the network history fields fo that configuration
310ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if userTriggered, we mark the configuration as "non selfAdded" since the user has seen it
311ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * and took over management
312ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if it is a "connect", remember which network were there at the point of the connect, so
313ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * as those networks get a relative lower score than the selected configuration
31462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle     *
315ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param netId
316ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param userTriggered : if the update come from WiFiManager
317ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param connect : if the update includes a connect
318117be607246604e875de62aa8cdd99700b77a2b4vandwalle     **/
31962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle    public void updateConfigurationHistory(int netId, boolean userTriggered, boolean connect) {
320f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration selected = mWifiConfigStore.getWifiConfiguration(netId);
321f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (selected == null) {
322f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return;
323f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
324f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
325e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        if (selected.SSID == null) {
326e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            return;
327e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        }
328e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
32962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        if (userTriggered) {
330ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            // reenable autojoin for this network,
33162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            // since the user want to connect to this configuration
33227355a942653264388e909a4276196ee63e57811vandwalle            selected.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
33362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            selected.selfAdded = false;
33462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        }
335f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
336992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (DBG && userTriggered) {
337f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (selected.connectChoices != null) {
338ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
339f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + Integer.toString(netId) + " now: "
340992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(selected.connectChoices.size())
341992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
342f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
343ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
344992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(netId)
345992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
346f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
347f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
348f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
349ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (connect && userTriggered) {
350ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            boolean found = false;
35162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            List<WifiConfiguration> networks =
35262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    mWifiConfigStore.getRecentConfiguredNetworks(12000, false);
35362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            if (networks != null) {
35462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                for (WifiConfiguration config : networks) {
355992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    if (DBG) {
356992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        logDbg("updateConfigurationHistory got " + config.SSID + " nid="
357992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                                + Integer.toString(config.networkId));
358992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    }
359f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
36062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (selected.configKey(true).equals(config.configKey(true))) {
361ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        found = true;
36262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        continue;
36362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
364f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
36562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    int rssi = WifiConfiguration.INVALID_RSSI;
36662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (config.visibility != null) {
36762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        rssi = config.visibility.rssi5;
36862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        if (config.visibility.rssi24 > rssi)
36962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                            rssi = config.visibility.rssi24;
37062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
37162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (rssi < -80) {
37262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        continue;
37362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
374f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
375ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    //the selected configuration was preferred over a recently seen config
376ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    //hence remember the user's choice:
377ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    //add the recently seen config to the selected's connectChoices array
378ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
379ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    if (selected.connectChoices == null) {
380ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        selected.connectChoices = new HashMap<String, Integer>();
381ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    }
382ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
383ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    logDbg("updateConfigurationHistory add a choice " + selected.configKey(true)
3840888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                            + " over " + config.configKey(true)
385992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                            + " RSSI " + Integer.toString(rssi));
386cf5b8eb8a08c45bd4a82f1f4bb789c8a1b08744fvandwalle
3870888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                    //add the visible config to the selected's connect choice list
38862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    selected.connectChoices.put(config.configKey(true), rssi);
389f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
39062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (config.connectChoices != null) {
391ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        if (VDBG) {
392ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                            logDbg("updateConfigurationHistory will remove "
39362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                    + selected.configKey(true) + " from " + config.configKey(true));
394ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        }
3950888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        //remove the selected from the recently seen config's connectChoice list
39662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        config.connectChoices.remove(selected.configKey(true));
3970888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle
3980888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        if (selected.linkedConfigurations != null) {
3990888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           //remove the selected's linked configuration from the
4000888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           //recently seen config's connectChoice list
4010888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           for (String key : selected.linkedConfigurations.keySet()) {
4020888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                               config.connectChoices.remove(key);
4030888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           }
4040888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        }
40562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
406ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                }
407ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                if (found == false) {
408ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     // log an error for now but do something stringer later
409ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     // we will need a new scan before attempting to connect to this
410ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     // configuration anyhow and thus we can process the scan results then
411ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     logDbg("updateConfigurationHistory try to connect to an old network!! : "
412ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                             + selected.configKey());
41362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
414f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
41562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                if (selected.connectChoices != null) {
41662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (VDBG)
417ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        logDbg("updateConfigurationHistory " + Integer.toString(netId)
41862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                + " now: " + Integer.toString(selected.connectChoices.size()));
41962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
420f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
421f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
422992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle
423992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        //TODO: write only if something changed
424992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (userTriggered || connect) {
425992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle            mWifiConfigStore.writeKnownNetworkHistory();
426992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        }
427f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
428f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
429f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void printChoices(WifiConfiguration config) {
430f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int num = 0;
431f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (config.connectChoices!= null) {
432f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            num = config.connectChoices.size();
433f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
434f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
435f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        logDbg("printChoices " + config.SSID + " num choices: " + Integer.toString(num));
436f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (config.connectChoices!= null) {
437f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            for (String key : config.connectChoices.keySet()) {
438f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                logDbg("                 " + key);
439f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
440f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
441f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
442f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
443f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    boolean hasConnectChoice(WifiConfiguration source, WifiConfiguration target) {
444f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        boolean found = false;
445f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (source == null)
446f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return false;
447f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (target == null)
448f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return false;
449f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
450f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (source.connectChoices != null) {
451f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ( source.connectChoices.get(target.configKey(true)) != null) {
452f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                found = true;
453f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
454f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
455f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
456f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (source.linkedConfigurations != null) {
457f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            for (String key : source.linkedConfigurations.keySet()) {
458f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(key);
459f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (config != null) {
460f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (config.connectChoices != null) {
461f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        if (config.connectChoices.get(target.configKey(true)) != null) {
462f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            found = true;
463f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        }
464f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
465f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
466f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
4674dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
468f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
469f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return found;
470f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
471f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
472f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    int compareWifiConfigurationsRSSI(WifiConfiguration a, WifiConfiguration b) {
473f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
474f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int boost5 = 25;
475f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility astatus = a.visibility;
476f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility bstatus = b.visibility;
477f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (astatus == null || bstatus == null) {
478453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            //error -> cant happen, need to throw en exception
479f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("compareWifiConfigurations NULL band status!");
480f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 0;
481f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
482453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if ((astatus.rssi5 > -70) && (bstatus.rssi5 == WifiConfiguration.INVALID_RSSI)
4834dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                && ((astatus.rssi5 + boost5) > (bstatus.rssi24))) {
484f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //a is seen on 5GHz with good RSSI, greater rssi than b
485f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //a is of higher priority - descending
486f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            order = -1;
487453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        } else if ((bstatus.rssi5 > -70) && (astatus.rssi5 == WifiConfiguration.INVALID_RSSI)
4884dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                && ((bstatus.rssi5 + boost5) > (bstatus.rssi24))) {
489f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //b is seen on 5GHz with good RSSI, greater rssi than a
490f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //a is of lower priority - ascending
491f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            order = 1;
492f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
493f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
494f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
495f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
4964dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
497f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    int compareWifiConfigurations(WifiConfiguration a, WifiConfiguration b) {
498f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
499117be607246604e875de62aa8cdd99700b77a2b4vandwalle        String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
500f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        boolean linked = false;
501f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
502453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if ((a.linkedConfigurations != null) && (b.linkedConfigurations != null)
503453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (a.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)
504453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (b.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)) {
505f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((a.linkedConfigurations.get(b.configKey(true))!= null)
506f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    && (b.linkedConfigurations.get(a.configKey(true))!= null)) {
507f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                linked = true;
508f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
509f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
510f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
511f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (a.ephemeral && b.ephemeral == false) {
512f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
513453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("compareWifiConfigurations ephemeral and prefers " + b.configKey()
514453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + a.configKey());
515f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
516f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 1; //b is of higher priority - ascending
517f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
518f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (b.ephemeral && a.ephemeral == false) {
519f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
520453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("compareWifiConfigurations ephemeral and prefers " +a.configKey()
521453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey());
522f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
523f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return -1; //a is of higher priority - descending
524f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
525f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
5264dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        int aRssiBoost5 = 0;
5274dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        int bRssiBoost5 = 0;
528453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        //apply Hysteresis: boost the RSSI value of the currently connected configuration
529453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        int aRssiBoost = 0;
530453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        int bRssiBoost = 0;
531453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if (null != mCurrentConfigurationKey) {
532453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            if (a.configKey().equals(mCurrentConfigurationKey)) {
533453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                aRssiBoost += 10;
534453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            } else if (b.configKey().equals(mCurrentConfigurationKey)) {
535453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                bRssiBoost += 10;
536453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            }
537453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        }
538f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (linked) {
5394dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            int ascore;
5404dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            int bscore;
541f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            // then we try prefer 5GHz, and try to ignore user's choice
542f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            WifiConfiguration.Visibility astatus = a.visibility;
543f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            WifiConfiguration.Visibility bstatus = b.visibility;
544f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (astatus == null || bstatus == null) {
545f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                //error
546f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                logDbg("compareWifiConfigurations NULL band status!");
547f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                return 0;
548f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
549f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
550f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG)  {
551f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                logDbg("compareWifiConfigurations linked: " + Integer.toString(astatus.rssi5)
552f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + "," + Integer.toString(astatus.rssi24) + "   "
553f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + Integer.toString(bstatus.rssi5) + ","
554f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + Integer.toString(bstatus.rssi24));
555f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
556f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
5574dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            //Boost RSSI value of 5GHz bands iff the base value is better than -65
5584dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            //This implements band preference where we prefer 5GHz if RSSI5 is good enough, whereas
5594dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            //we prefer 2.4GHz otherwise.
5604dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            //Note that 2.4GHz doesn't need a boost since at equal power the RSSI is 6-10 dB higher
5614dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if ((astatus.rssi5+aRssiBoost) > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) {
5624dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                aRssiBoost5 = 25;
5634dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
5644dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if ((bstatus.rssi5+bRssiBoost) > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) {
5654dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                bRssiBoost5 = 25;
5664dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
567f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
5684dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (astatus.rssi5+aRssiBoost5 > astatus.rssi24) {
5694dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                //prefer a's 5GHz
5704dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                ascore = astatus.rssi5 + aRssiBoost5 + aRssiBoost;
5714dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            } else {
5724dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                //prefer a's 2.4GHz
5734dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                ascore = astatus.rssi24 + aRssiBoost;
5744dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
5754dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (bstatus.rssi5+bRssiBoost5 > bstatus.rssi24) {
5764dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                //prefer b's 5GHz
5774dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                bscore = bstatus.rssi5 + bRssiBoost5 + bRssiBoost;
5784dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            } else {
5794dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                //prefer b's 2.4GHz
5804dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                bscore = bstatus.rssi24 + bRssiBoost;
5814dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
5824dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (ascore > bscore) {
5834dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                //a is seen on 5GHz with good RSSI, greater rssi than b
5844dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                //a is of higher priority - descending
5854dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                order = -10;
586f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG) {
587453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("compareWifiConfigurations linked and prefers " + a.configKey()
5884dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " rssi=(" + a.visibility.rssi24
5894dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + a.visibility.rssi5
5904dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + a.visibility.num24
5914dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + a.visibility.num5 + ")"
592453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + " over " + b.configKey()
5934dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " rssi=(" + b.visibility.rssi24
5944dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + b.visibility.rssi5
5954dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + b.visibility.num24
5964dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + b.visibility.num5 + ")"
5974dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " due to RSSI");
598f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
5994dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            } else if (bscore > ascore) {
6004dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                //b is seen on 5GHz with good RSSI, greater rssi than a
6014dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                //a is of lower priority - ascending
6024dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                order = 10;
6034dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                if (VDBG) {
604453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("compareWifiConfigurations linked and prefers " + b.configKey()
6054dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " rssi=(" + b.visibility.rssi24
6064dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + b.visibility.rssi5
6074dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + b.visibility.num24
6084dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + b.visibility.num5 + ")"
6094dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " over " + a.configKey()
6104dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " rssi=(" + a.visibility.rssi24
6114dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + a.visibility.rssi5
6124dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + a.visibility.num24
6134dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + a.visibility.num5 + ")"
6144dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " due to RSSI");
615f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
616f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
617f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
618ede1310be531a84faa08f02c3fd243448dd936ddvandwalle
619ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        //compare by user's choice.
620f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (hasConnectChoice(a, b)) {
621f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //a is of higher priority - descending
622f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            order = order -2;
623f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG)   {
624453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("compareWifiConfigurations prefers -2 " + a.configKey()
625453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey()
626ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        + " due to user choice order -> " + Integer.toString(order));
627f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
628f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
629f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
630f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (hasConnectChoice(b, a)) {
631f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //a is of lower priority - ascending
632f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            order = order + 2;
633f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG)   {
634453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("compareWifiConfigurations prefers +2 " + b.configKey() + " over "
635453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + a.configKey() + " due to user choice order ->" + Integer.toString(order));
636f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
637f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
638f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
639ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        //TODO count the number of association rejection
640ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        // and use this to adjust the order by more than +/- 3
641ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        if ((a.status == WifiConfiguration.Status.DISABLED)
642ede1310be531a84faa08f02c3fd243448dd936ddvandwalle                && (a.disableReason == WifiConfiguration.DISABLED_ASSOCIATION_REJECT)) {
643ede1310be531a84faa08f02c3fd243448dd936ddvandwalle            //a is of lower priority - ascending
644ede1310be531a84faa08f02c3fd243448dd936ddvandwalle            //lower the comparison score a bit
645ede1310be531a84faa08f02c3fd243448dd936ddvandwalle            order = order +3;
646ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        }
647ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        if ((b.status == WifiConfiguration.Status.DISABLED)
648ede1310be531a84faa08f02c3fd243448dd936ddvandwalle                && (b.disableReason == WifiConfiguration.DISABLED_ASSOCIATION_REJECT)) {
649ede1310be531a84faa08f02c3fd243448dd936ddvandwalle            //a is of higher priority - descending
650ede1310be531a84faa08f02c3fd243448dd936ddvandwalle            //lower the comparison score a bit
651ede1310be531a84faa08f02c3fd243448dd936ddvandwalle            order = order -3;
652ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        }
653ede1310be531a84faa08f02c3fd243448dd936ddvandwalle
654ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if ((lastSelectedConfiguration != null)
655ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                && a.configKey().equals(lastSelectedConfiguration)) {
6564dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            // a is the last selected configuration, so keep it above connect choices (+/-2) and
6574dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            // above RSSI based selection of linked configuration (+/- 11)
6584dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            // by giving a -11
659c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            // Additional other factors like BAD RSSI (still to do) and
660c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            // ASSOC_REJECTION high counts will then still
6614dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            // tip the auto-join to roam
6624dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            order = order - 11;
663ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            if (VDBG)   {
6644dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                logDbg("compareWifiConfigurations prefers -11 " + a.configKey()
665453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey() + " because a is the last selected -> "
666ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        + Integer.toString(order));
667ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            }
668ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        } else if ((lastSelectedConfiguration != null)
669ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                && b.configKey().equals(lastSelectedConfiguration)) {
6704dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            // b is the last selected configuration, so keep it above connect choices (+/-2) and
6714dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            // above RSSI based selection of linked configuration (+/- 11)
6724dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            // by giving a +11
673c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            // Additional other factors like BAD RSSI (still to do) and
674c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            // ASSOC_REJECTION high counts will then still
6754dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            // tip the auto-join to roam
6764dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            order = order + 11;
677ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            if (VDBG)   {
6784dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                logDbg("compareWifiConfigurations prefers +11 " + a.configKey()
679453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey() + " because b is the last selected -> "
680ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        + Integer.toString(order));
681ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            }
682ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        }
683ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
684f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order == 0) {
685f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //we don't know anything - pick the last seen i.e. K behavior
686f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //we should do this only for recently picked configurations
687f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (a.priority > b.priority) {
688f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                //a is of higher priority - descending
689f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)   {
690453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("compareWifiConfigurations prefers -1 " + a.configKey() + " over "
691453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + b.configKey() + " due to priority");
692f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
693f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
694f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                order = -1;
695f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else if (a.priority < b.priority) {
696f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                //a is of lower priority - ascending
697f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)  {
698453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("compareWifiConfigurations prefers +1 " + b.configKey() + " over "
699453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + a.configKey() + " due to priority");
700f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
701f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
702f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle              order = 1;
703f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
704f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                //maybe just look at RSSI or band
705f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)  {
706453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("compareWifiConfigurations prefers +1 " + b.configKey() + " over "
707453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + a.configKey() + " due to nothing");
708f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
709f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
710f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                order = compareWifiConfigurationsRSSI(a, b); //compare RSSI
711f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
712f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
713f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
714f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String sorder = " == ";
715f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order > 0)
716f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " < ";
717f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order < 0)
718f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " > ";
719f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
720f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG)   {
721453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            logDbg("compareWifiConfigurations Done: " + a.configKey() + sorder
722453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    + b.configKey() + " order " + Integer.toString(order));
723f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
724f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
725f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
726f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
727f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
728b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    /* attemptRoam function implement the core of the same SSID switching algorithm */
729b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    ScanResult attemptRoam(WifiConfiguration current, int age) {
7304dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        ScanResult a = null;
731b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current == null) {
732b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
733b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam not associated");
734b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
7354dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            return null;
7364dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
737b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current.scanResultCache == null) {
738b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
739b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam no scan cache");
740b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
7414dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            return null;
7424dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
743b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle        if (current.scanResultCache.size() > 6) {
744b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
745c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptRoam scan cache size "
746c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + current.scanResultCache.size() + " --> bail");
747b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
748c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            //implement same SSID roaming only for configurations
749c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            // that have less than 4 BSSIDs
7504dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            return null;
7514dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
752b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        String currentBSSID = mWifiStateMachine.getCurrentBSSID();
753b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (currentBSSID == null) {
754b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (DBG)   {
755b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam currentBSSID unknown");
756b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
757b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            return null;
758b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
759b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
760b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current.bssidOwnerUid!= 0 && current.bssidOwnerUid != Process.WIFI_UID) {
761b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (DBG)   {
762c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptRoam BSSID owner is "
763c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + Long.toString(current.bssidOwnerUid) + " -> bail");
764b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
7654dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            return null;
7664dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
7674dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
768c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle        //determine which BSSID we want to associate to, taking account
769c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle        // relative strength of 5 and 2.4 GHz BSSIDs
7704dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        long now_ms = System.currentTimeMillis();
7714dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        int bRssiBoost5 = 0;
7724dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        int aRssiBoost5 = 0;
7734dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        int bRssiBoost = 0;
7744dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        int aRssiBoost = 0;
775b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        for (ScanResult b : current.scanResultCache.values()) {
7764dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
7773a2a3d226881cce8a4e511302231d843b0def303vandwalle            if ((b.seen == 0) || (b.BSSID == null)) {
7784dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
7793a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
7804dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
7813a2a3d226881cce8a4e511302231d843b0def303vandwalle            if (b.status != ScanResult.ENABLED) {
7824dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
7833a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
7844dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
7854dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if ((now_ms - b.seen) > age) continue;
7864dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
7874dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            //pick first one
7884dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (a == null) {
7894dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                a = b;
7904dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
7914dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
7924dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
793b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (currentBSSID.equals(b.BSSID)) {
794c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                //reduce the benefit of hysteresis if RSSI <= -75
795c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                if (b.level <= WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD) {
796c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    bRssiBoost = +6;
797c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
798c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    bRssiBoost = +10;
799c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
8004dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
801b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (currentBSSID.equals(a.BSSID)) {
802c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                if (a.level <= WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD) {
803c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    //reduce the benefit of hysteresis if RSSI <= -75
804c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    aRssiBoost = +6;
805c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
806c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    aRssiBoost = +10;
807c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
8084dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
809c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            if (b.is5GHz() && (b.level+bRssiBoost)
810c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) {
8114dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                bRssiBoost5 = 25;
812c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            } else if (b.is5GHz() && (b.level+bRssiBoost)
813c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    < WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD) {
814c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                bRssiBoost5 = -10;
8154dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
816c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            if (a.is5GHz() && (a.level+aRssiBoost)
817c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) {
8184dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                aRssiBoost5 = 25;
819c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            } else if (a.is5GHz() && (a.level+aRssiBoost)
820c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    < WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD) {
821c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                aRssiBoost5 = -10;
8224dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
8234dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
8244dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (VDBG)  {
825c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                String comp = " < ";
826c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
827c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    comp = " > ";
828c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
8294dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                logDbg("attemptRoam: "
830c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + b.BSSID + " rssi=" + b.level + " boost=" + Integer.toString(bRssiBoost)
831c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + "/" + Integer.toString(bRssiBoost5) + " freq=" + b.frequency + comp
832c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + a.BSSID + " rssi=" + a.level + " boost=" + Integer.toString(aRssiBoost)
833c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + "/" + Integer.toString(aRssiBoost5) + " freq=" + a.frequency);
834c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            }
835c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle
836c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
837c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                //b is the better BSSID
838c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                a = b;
8394dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
8404dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
8413a2a3d226881cce8a4e511302231d843b0def303vandwalle        if (a != null) {
8423a2a3d226881cce8a4e511302231d843b0def303vandwalle            if (VDBG)  {
8433a2a3d226881cce8a4e511302231d843b0def303vandwalle                logDbg("attemptRoam: Found "
8443a2a3d226881cce8a4e511302231d843b0def303vandwalle                        + a.BSSID + " rssi=" + a.level + " freq=" + a.frequency
8453a2a3d226881cce8a4e511302231d843b0def303vandwalle                        + " Current: " + currentBSSID);
8463a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
8473a2a3d226881cce8a4e511302231d843b0def303vandwalle            if (currentBSSID.equals(a.BSSID)) {
8483a2a3d226881cce8a4e511302231d843b0def303vandwalle                return null;
8493a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
8504dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
8513a2a3d226881cce8a4e511302231d843b0def303vandwalle        return a;
8524dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    }
8534dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
8544dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    /* attemptAutoJoin function implement the core of the a network switching algorithm */
855f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void attemptAutoJoin() {
856b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        int networkSwitchType = AUTO_JOIN_IDLE;
8574dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
8588c9088d11880553458f09377cc60d6eb7e66747bvandwalle        String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
8598c9088d11880553458f09377cc60d6eb7e66747bvandwalle
86027355a942653264388e909a4276196ee63e57811vandwalle        // reset the currentConfiguration Key, and set it only if WifiStateMachine and
861453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        // supplicant agree
862453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        mCurrentConfigurationKey = null;
863453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        WifiConfiguration currentConfiguration = mWifiStateMachine.getCurrentWifiConfiguration();
864453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
865f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration candidate = null;
866f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
867f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        /* obtain the subset of recently seen networks */
86827355a942653264388e909a4276196ee63e57811vandwalle        List<WifiConfiguration> list = mWifiConfigStore.getRecentConfiguredNetworks(3000, false);
869f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (list == null) {
870f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG)  logDbg("attemptAutoJoin nothing");
871f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return;
872f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
873f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
874f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        /* find the currently connected network: ask the supplicant directly */
875f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String val = mWifiNative.status();
876f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String status[] = val.split("\\r?\\n");
877f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
878f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("attemptAutoJoin() status=" + val + " split="
879f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(status.length));
880f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
881f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
882b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        int supplicantNetId = -1;
883f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (String key : status) {
884f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (key.regionMatches(0, "id=", 0, 3)) {
885f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int idx = 3;
886b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                supplicantNetId = 0;
887f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                while (idx < key.length()) {
888f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    char c = key.charAt(idx);
889f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
890f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if ((c >= 0x30) && (c <= 0x39)) {
891b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        supplicantNetId *= 10;
892b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        supplicantNetId += c - 0x30;
893f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        idx++;
894f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    } else {
895f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        break;
896f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
897f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
898f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
899f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
900ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (DBG) {
901ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            logDbg("attemptAutoJoin() num recent config " + Integer.toString(list.size())
902b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                    + " ---> suppId=" + Integer.toString(supplicantNetId));
903ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
904f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
905453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if (currentConfiguration != null) {
906b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            if (supplicantNetId != currentConfiguration.networkId) {
907453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("attemptAutoJoin() ERROR wpa_supplicant out of sync nid="
908b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        + Integer.toString(supplicantNetId) + " WifiStateMachine="
909453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + Integer.toString(currentConfiguration.networkId));
910b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                mWifiStateMachine.disconnectCommand();
911b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                return;
912453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            } else {
913453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                mCurrentConfigurationKey = currentConfiguration.configKey();
914453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            }
915453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        }
916453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
917b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        int currentNetId = -1;
918b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentConfiguration != null) {
919b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            // if we are associated to a configuration, it will
920b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            // be compared thru the compareNetwork function
921b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            currentNetId = currentConfiguration.networkId;
922b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
923b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle
924c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle        /* run thru all visible configurations without looking at the one we
925c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle         * are currently associated to
9264dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle         * select Best Network candidate from known WifiConfigurations
9274dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle         * */
928f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (WifiConfiguration config : list) {
929f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((config.status == WifiConfiguration.Status.DISABLED)
930f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    && (config.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE)) {
931ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
932b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("attemptAutoJoin skip candidate due to auth failure: "
933ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + config.configKey(true));
934ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
935f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
936f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
937453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
938e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            if (config.SSID == null) {
939b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                continue;
940e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            }
941e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
94227355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
94327355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
944453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                //avoid temporarily disabled networks altogether
9454dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                //TODO: implement a better logic which will re-enable the network after some time
946ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
947ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                    logDbg("attemptAutoJoin skip candidate due to auto join status "
948ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + Integer.toString(config.autoJoinStatus) + " key "
949ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + config.configKey(true));
950ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
951f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
952f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
953f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
95427355a942653264388e909a4276196ee63e57811vandwalle            //try to unblacklist based on elapsed time
95527355a942653264388e909a4276196ee63e57811vandwalle            if (config.blackListTimestamp > 0) {
95627355a942653264388e909a4276196ee63e57811vandwalle                long now = System.currentTimeMillis();
95727355a942653264388e909a4276196ee63e57811vandwalle                if (now < config.blackListTimestamp) {
958c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    //looks like there was a change in the system clock since we black listed, and
95927355a942653264388e909a4276196ee63e57811vandwalle                    //timestamp is not meaningful anymore, hence lose it.
96027355a942653264388e909a4276196ee63e57811vandwalle                    //this event should be rare enough so that we still want to lose the black list
96127355a942653264388e909a4276196ee63e57811vandwalle                    config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
96227355a942653264388e909a4276196ee63e57811vandwalle                } else {
9634dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    if ((now - config.blackListTimestamp) > loseBlackListHardMilli) {
96427355a942653264388e909a4276196ee63e57811vandwalle                        //reenable it after 18 hours, i.e. next day
96527355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
9664dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    } else if ((now - config.blackListTimestamp) > loseBlackListSoftMilli) {
96727355a942653264388e909a4276196ee63e57811vandwalle                        //lose blacklisting due to bad link
96827355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(config.autoJoinStatus - 8);
96927355a942653264388e909a4276196ee63e57811vandwalle                    }
97027355a942653264388e909a4276196ee63e57811vandwalle                }
97127355a942653264388e909a4276196ee63e57811vandwalle            }
97227355a942653264388e909a4276196ee63e57811vandwalle
97327355a942653264388e909a4276196ee63e57811vandwalle            //try to unblacklist based on good visibility
97427355a942653264388e909a4276196ee63e57811vandwalle            if (config.visibility.rssi5 < WifiConfiguration.UNBLACKLIST_THRESHOLD_5_SOFT
97527355a942653264388e909a4276196ee63e57811vandwalle                    && config.visibility.rssi24 < WifiConfiguration.UNBLACKLIST_THRESHOLD_24_SOFT) {
97627355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
97727355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin skip candidate due to auto join status "
9784dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.autoJoinStatus
9794dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " key " + config.configKey(true)
9804dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " rssi=(" + config.visibility.rssi24
9814dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.rssi5
9824dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
9834dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
98427355a942653264388e909a4276196ee63e57811vandwalle                }
98527355a942653264388e909a4276196ee63e57811vandwalle            } else if (config.visibility.rssi5 < WifiConfiguration.UNBLACKLIST_THRESHOLD_5_HARD
98627355a942653264388e909a4276196ee63e57811vandwalle                    && config.visibility.rssi24 < WifiConfiguration.UNBLACKLIST_THRESHOLD_24_HARD) {
98727355a942653264388e909a4276196ee63e57811vandwalle                // if the network is simply temporary disabled, don't allow reconnect until
98827355a942653264388e909a4276196ee63e57811vandwalle                // rssi becomes good enough
98927355a942653264388e909a4276196ee63e57811vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 1);
99027355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
99127355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped soft -> status="
99227355a942653264388e909a4276196ee63e57811vandwalle                            + config.autoJoinStatus
9934dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " key " + config.configKey(true) + " rssi=("
9944dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
9954dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
9964dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
99727355a942653264388e909a4276196ee63e57811vandwalle                }
99827355a942653264388e909a4276196ee63e57811vandwalle            } else {
999c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 3);
100027355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
100127355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped hard -> status="
100227355a942653264388e909a4276196ee63e57811vandwalle                            + config.autoJoinStatus
10034dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " key " + config.configKey(true) + " rssi=("
10044dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
10054dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
10064dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
100727355a942653264388e909a4276196ee63e57811vandwalle                }
100827355a942653264388e909a4276196ee63e57811vandwalle            }
100927355a942653264388e909a4276196ee63e57811vandwalle
101027355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
101127355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED) {
101227355a942653264388e909a4276196ee63e57811vandwalle                //network is blacklisted, skip
10134dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                if (DBG) {
10144dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    logDbg("attemptAutoJoin skip blacklisted -> status="
10154dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.autoJoinStatus
10164dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " key " + config.configKey(true) + " rssi=("
10174dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
10184dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
10194dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
10204dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                }
102127355a942653264388e909a4276196ee63e57811vandwalle                continue;
102227355a942653264388e909a4276196ee63e57811vandwalle            }
1023f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (config.networkId == currentNetId) {
1024ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
102521bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    logDbg("attemptAutoJoin skip current candidate  "
102621bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                            + Integer.toString(currentNetId)
1027ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + " key " + config.configKey(true));
1028ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
1029f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1030f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1031f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
103221bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle            if (lastSelectedConfiguration == null ||
103321bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    !config.configKey().equals(lastSelectedConfiguration)) {
10348c9088d11880553458f09377cc60d6eb7e66747bvandwalle                //don't try to autojoin a network that is too far
10358c9088d11880553458f09377cc60d6eb7e66747bvandwalle                if (config.visibility == null) {
10368c9088d11880553458f09377cc60d6eb7e66747bvandwalle                    continue;
10378c9088d11880553458f09377cc60d6eb7e66747bvandwalle                }
103827355a942653264388e909a4276196ee63e57811vandwalle                if (config.visibility.rssi5 < WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_5
1039c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        && config.visibility.rssi24
1040c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        < WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_24) {
10414dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    if (DBG) {
10424dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                        logDbg("attemptAutoJoin gskip due to low visibility -> status="
10434dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + config.autoJoinStatus
10444dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + " key " + config.configKey(true) + " rssi="
10454dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + config.visibility.rssi24 + ", " + config.visibility.rssi5
10464dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + " num=" + config.visibility.num24
10474dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + ", " + config.visibility.num5);
10484dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    }
10498c9088d11880553458f09377cc60d6eb7e66747bvandwalle                    continue;
10508c9088d11880553458f09377cc60d6eb7e66747bvandwalle                }
10518c9088d11880553458f09377cc60d6eb7e66747bvandwalle            }
10528c9088d11880553458f09377cc60d6eb7e66747bvandwalle
1053ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            if (DBG) {
1054c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptAutoJoin trying candidate id="
1055c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + Integer.toString(config.networkId) + " "
10564dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                        + config.SSID + " key " + config.configKey(true)
10574dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                        + " status=" + config.autoJoinStatus);
1058ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            }
1059f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1060f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate == null) {
1061f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                candidate = config;
1062f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
1063f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)  {
1064453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("attemptAutoJoin will compare candidate  " + candidate.configKey()
10654dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " with " + config.configKey());
1066f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1067f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1068f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int order = compareWifiConfigurations(candidate, config);
1069f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (order > 0) {
1070f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    //ascending : candidate < config
1071f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    candidate = config;
1072f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1073f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1074f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1075f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1076f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        /* now, go thru scan result to try finding a better Herrevad network */
1077f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (mNetworkScoreCache != null) {
1078f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi5 = WifiConfiguration.INVALID_RSSI;
1079f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi24 = WifiConfiguration.INVALID_RSSI;
1080f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            WifiConfiguration.Visibility visibility;
1081f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate != null) {
1082f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi5 = candidate.visibility.rssi5;
1083f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi24 = candidate.visibility.rssi24;
1084f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1085f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1086f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //get current date
1087b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            long now_ms = System.currentTimeMillis();
1088f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1089f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (rssi5 < -60 && rssi24 < -70) {
1090f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                for (ScanResult result : scanResultCache.values()) {
1091f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if ((now_ms - result.seen) < 3000) {
1092f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        int score = mNetworkScoreCache.getNetworkScore(result);
1093f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        if (score > 0) {
1094f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            // try any arbitrary formula for now, adding apple and oranges,
1095f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            // i.e. adding network score and "dBm over noise"
10964dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                           if (result.is24GHz()) {
1097f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                if ((result.level + score) > (rssi24 -40)) {
1098f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    // force it as open, TBD should we otherwise verify that this
1099f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    // BSSID only supports open??
1100f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    result.capabilities = "";
1101f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1102f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    //switch to this scan result
1103f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    candidate =
1104c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                                          mWifiConfigStore.wifiConfigurationFromScanResult(result);
1105f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    candidate.ephemeral = true;
1106f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                }
1107f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                           } else {
1108f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                if ((result.level + score) > (rssi5 -30)) {
1109f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    // force it as open, TBD should we otherwise verify that this
1110f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    // BSSID only supports open??
1111f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    result.capabilities = "";
1112f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1113f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    //switch to this scan result
1114f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    candidate =
1115c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                                          mWifiConfigStore.wifiConfigurationFromScanResult(result);
1116f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    candidate.ephemeral = true;
1117f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                }
1118f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                           }
1119f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        }
1120f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
1121f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1122f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1123f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1124b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
1125b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        /* if candidate is found, check the state of the connection so as
11264dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            to decide if we should be acting on this candidate and switching over */
1127b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        int networkDelta = compareNetwork(candidate);
1128b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (DBG && candidate != null) {
1129b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            logDbg("attemptAutoJoin compare SSID candidate : delta="
1130b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                    + Integer.toString(networkDelta) + " "
1131b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                    + candidate.configKey()
1132c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    + " linked=" + (currentConfiguration != null
1133c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    && currentConfiguration.isLinked(candidate)));
1134b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
11354dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1136b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        /* ASK WifiStateMachine permission to switch:
1137b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            for instance,
1138b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if user is currently streaming voice traffic,
1139b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            then don’t switch regardless of the delta
1140b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            */
1141b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (mWifiStateMachine.shouldSwitchNetwork(networkDelta)) {
1142b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (mStaStaSupported) {
1143b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("mStaStaSupported --> error do nothing now ");
1144b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            } else {
1145b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (currentConfiguration != null && currentConfiguration.isLinked(candidate)) {
1146b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_EXTENDED_ROAMING;
1147b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                } else {
1148b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_OUT_OF_NETWORK_ROAMING;
1149b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1150b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1151b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto connect with netId "
1152b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(candidate.networkId)
1153b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " to " + candidate.configKey());
1154b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1155b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT,
1156b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                        candidate.networkId, networkSwitchType, candidate);
11574dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
1158b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
11594dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1160b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (networkSwitchType == AUTO_JOIN_IDLE) {
1161b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            //attempt same WifiConfiguration roaming
1162b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            ScanResult roamCandidate = attemptRoam(currentConfiguration, 3000);
1163b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (roamCandidate != null) {
1164b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1165b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto roam with netId "
1166b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(currentConfiguration.networkId)
1167b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " " + currentConfiguration.configKey() + " to BSSID="
1168b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + roamCandidate.BSSID + " freq=" + roamCandidate.frequency
1169b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " RSSI=" + roamCandidate.frequency);
1170b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1171b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                networkSwitchType = AUTO_JOIN_ROAMING;
1172b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_ROAM,
1173b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                            currentConfiguration.networkId, 1, roamCandidate);
1174f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1175f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1176b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (VDBG) logDbg("Done attemptAutoJoin status=" + Integer.toString(networkSwitchType));
1177f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
1178f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle}
1179f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1180