WifiAutoJoinController.java revision 27355a942653264388e909a4276196ee63e57811
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;
29f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.util.Log;
30f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
310c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport java.util.ArrayList;
320c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport java.util.Collection;
33f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.Iterator;
34f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.HashMap;
35f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.List;
36f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.Date;
37f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
38f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle/**
39f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * AutoJoin controller is responsible for WiFi Connect decision
40f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
41f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * It runs in the thread context of WifiStateMachine
42f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
43f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle */
44f22d23092ab37286a5ef9d257d5bb32c421d2669vandwallepublic class WifiAutoJoinController {
45f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
46f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private Context mContext;
47f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiStateMachine mWifiStateMachine;
48f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiConfigStore mWifiConfigStore;
49f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiTrafficPoller mWifiTrafficPoller;
50f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNative mWifiNative;
51f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
52f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private NetworkScoreManager scoreManager;
53f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNetworkScoreCache mNetworkScoreCache;
54f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
55f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final String TAG = "WifiAutoJoinController ";
56ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean DBG = false;
57ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean VDBG = false;
58f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final boolean mStaStaSupported = false;
59f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final int SCAN_RESULT_CACHE_SIZE = 80;
60f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
61453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle    private String mCurrentConfigurationKey = null; //used by autojoin
62f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
63f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private HashMap<String, ScanResult> scanResultCache =
64f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            new HashMap<String, ScanResult>();
65f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
6627355a942653264388e909a4276196ee63e57811vandwalle    //lose the non-auth failure blacklisting after 8 hours
6727355a942653264388e909a4276196ee63e57811vandwalle    private final static long loseBlackListHardMilly = 1000 * 60 * 60 * 8;
6827355a942653264388e909a4276196ee63e57811vandwalle    //lose some temporary blacklisting after 30 minutes
6927355a942653264388e909a4276196ee63e57811vandwalle    private final static long loseBlackListSoftMilly = 1000 * 60 * 30;
7027355a942653264388e909a4276196ee63e57811vandwalle
7127355a942653264388e909a4276196ee63e57811vandwalle
72f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    WifiAutoJoinController(Context c, WifiStateMachine w, WifiConfigStore s,
73f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                           WifiTrafficPoller t, WifiNative n) {
74f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mContext = c;
75f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiStateMachine = w;
76f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore = s;
77f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiTrafficPoller = t;
78f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiNative = n;
79f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mNetworkScoreCache = null;
8021bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle        scoreManager =
8121bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                (NetworkScoreManager) mContext.getSystemService(Context.NETWORK_SCORE_SERVICE);
82f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager == null)
83f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("Registered scoreManager NULL " + " service " + Context.NETWORK_SCORE_SERVICE);
84f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
85f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager != null) {
86f13817203179f41620514718c8668ae7e418f8afJeff Davidson            mNetworkScoreCache = new WifiNetworkScoreCache(mContext);
87f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            scoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
88f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        } else {
89f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("No network score service: Couldnt register as a WiFi score Manager, type="
90f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(NetworkKey.TYPE_WIFI)
91f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + " service " + Context.NETWORK_SCORE_SERVICE);
92f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            mNetworkScoreCache = null;
93f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
94f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
95f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
96ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    void enableVerboseLogging(int verbose) {
97ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (verbose > 0 ) {
98abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = true;
99ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = true;
100ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        } else {
101abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = false;
102ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = false;
103ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
104ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    }
105ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle
10621bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle    int mScanResultMaximumAge = 30000; /* milliseconds unit */
107f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
108ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    /*
109ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * flush out scan results older than mScanResultMaximumAge
110ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     *
111ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * */
112f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private void ageScanResultsOut(int delay) {
113f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (delay <= 0) {
114f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            delay = mScanResultMaximumAge; //something sane
115f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
116f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        Date now = new Date();
117f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        long milli = now.getTime();
118f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
119f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("ageScanResultsOut delay " + Integer.valueOf(delay) + " size "
120f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.valueOf(scanResultCache.size()) + " now " + Long.valueOf(milli));
121f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
122f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
123f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        Iterator<HashMap.Entry<String,ScanResult>> iter = scanResultCache.entrySet().iterator();
124f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        while (iter.hasNext()) {
125f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            HashMap.Entry<String,ScanResult> entry = iter.next();
126f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult result = entry.getValue();
127f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
128f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((result.seen + delay) < milli) {
129f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                iter.remove();
130f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
131f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
132f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
133f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
134f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void addToScanCache(List<ScanResult> scanList) {
135f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration associatedConfig;
136f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1370c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        ArrayList<NetworkKey> unknownScanResults = new ArrayList<NetworkKey>();
1380c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
139f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for(ScanResult result: scanList) {
1401fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng            if (result.SSID == null) continue;
141f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            result.seen = System.currentTimeMillis();
142f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
143f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult sr = scanResultCache.get(result.BSSID);
144f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (sr != null) {
145f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                // if there was a previous cache result for this BSSID, average the RSSI values
146f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
147f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int previous_rssi = sr.level;
148f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                long previously_seen_milli = sr.seen;
149f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
150f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                /* average RSSI with previously seen instances of this scan result */
151f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int avg_rssi = result.level;
152f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
153f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if ((previously_seen_milli > 0)
154f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        && (previously_seen_milli < mScanResultMaximumAge/2)) {
155f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    /*
156f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    *
157f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    * previously_seen_milli = 0 => RSSI = 0.5 * previous_seen_rssi + 0.5 * new_rssi
158f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    *
159f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    * If previously_seen_milli is 15+ seconds old:
160f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    *      previously_seen_milli = 15000 => RSSI = new_rssi
161f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    *
162f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    */
163f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
164f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    double alpha = 0.5 - (double)previously_seen_milli
165f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            / (double)mScanResultMaximumAge;
166f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
167f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    avg_rssi = (int)((double)avg_rssi * (1-alpha) + (double)previous_rssi * alpha);
168f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
169f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                result.level = avg_rssi;
170f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
171f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                //remove the previous Scan Result
172f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                scanResultCache.remove(result.BSSID);
1730c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            } else {
1740c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                if (!mNetworkScoreCache.isScoredNetwork(result)) {
17521bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    WifiKey wkey;
17621bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    //TODO : find out how we can get there without a valid UTF-8 encoded SSID
17721bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    //TODO: which will cause WifiKey constructor to fail
17821bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    try {
17921bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        wkey = new WifiKey("\"" + result.SSID + "\"", result.BSSID);
18021bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    } catch (IllegalArgumentException e) {
18121bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        logDbg("AutoJoinController: received badly encoded SSID=[" + result.SSID +
18221bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                                "] ->skipping this network");
18321bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        wkey = null;
18421bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    }
18521bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    if (wkey != null) {
18621bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        NetworkKey nkey = new NetworkKey(wkey);
18721bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        //if we don't know this scan result then request a score to Herrevad
18821bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        unknownScanResults.add(nkey);
18921bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    }
1900c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                }
191f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
192f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
193f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            scanResultCache.put(result.BSSID, new ScanResult(result));
194f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
195f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //add this BSSID to the scanResultCache of the relevant WifiConfiguration
196f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            associatedConfig = mWifiConfigStore.updateSavedNetworkHistory(result);
197f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1980c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            //try to associate this BSSID to an existing Saved WifiConfiguration
199f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (associatedConfig == null) {
200f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                associatedConfig = mWifiConfigStore.associateWithConfiguration(result);
2011fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng                if (associatedConfig != null && associatedConfig.SSID != null) {
202f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (VDBG) {
203f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        logDbg("addToScanCache save associated config "
204f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                + associatedConfig.SSID + " with " + associatedConfig.SSID);
205f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
206f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    mWifiStateMachine.sendMessage(WifiManager.SAVE_NETWORK, associatedConfig);
207f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
208f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
209f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
2100c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
2110c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        if (unknownScanResults.size() != 0) {
2120c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            NetworkKey[] newKeys =
2130c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                    unknownScanResults.toArray(new NetworkKey[unknownScanResults.size()]);
2140c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                //kick the score manager, we will get updated scores asynchronously
2150c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            scoreManager.requestScores(newKeys);
2160c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        }
217f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
218f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
219f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void logDbg(String message) {
2200888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle        logDbg(message, false);
221ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    }
222ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
223ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    void logDbg(String message, boolean stackTrace) {
224f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        long now = SystemClock.elapsedRealtimeNanos();
2250888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle        String ts = String.format("[%,d us] ", now / 1000);
226ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (stackTrace) {
227ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            Log.e(TAG, ts + message + " stack:"
228ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[2].getMethodName() + " - "
229ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[3].getMethodName() + " - "
230ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[4].getMethodName() + " - "
231ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[5].getMethodName());
232ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        } else {
233ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            Log.e(TAG, ts + message);
234ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        }
235f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
236f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
237f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    /* called directly from WifiStateMachine  */
238f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void newSupplicantResults() {
239f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        List<ScanResult> scanList = mWifiStateMachine.syncGetScanResultsList();
240f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        addToScanCache(scanList);
241f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(mScanResultMaximumAge);
242f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (DBG)
243f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle           logDbg("newSupplicantResults size=" + Integer.valueOf(scanResultCache.size()) );
244f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
245f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
246f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore.writeKnownNetworkHistory();
247f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
248f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
249f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
250f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
251f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    /* not used at the moment
252f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * should be a call back from WifiScanner HAL ??
253f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * this function is not hooked and working yet, it will receive scan results from WifiScanners
254f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * with the list of IEs,then populate the capabilities by parsing the IEs and inject the scan
255f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * results as normal.
256f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     */
257f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void newHalScanResults() {
258f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        List<ScanResult> scanList = null;//mWifiScanner.syncGetScanResultsList();
259f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String akm = WifiParser.parse_akm(null, null);
260f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        logDbg(akm);
261f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        addToScanCache(scanList);
262f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(0);
263f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
264f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore.writeKnownNetworkHistory();
265f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
266f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
267f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    /* network link quality changed, called directly from WifiTrafficPoller,
268f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    or by listening to Link Quality intent */
269f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void linkQualitySignificantChange() {
270f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
271f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
272f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
273f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    /*
274f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * compare a WifiConfiguration against the current network, return a delta score
275f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * If not associated, and the candidate will always be better
276f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * For instance if the candidate is a home network versus an unknown public wifi,
277f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * the delta will be infinite, else compare Kepler scores etc…
278f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     ***/
279f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private int compareNetwork(WifiConfiguration candidate) {
280f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration currentNetwork = mWifiStateMachine.getCurrentWifiConfiguration();
281f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (currentNetwork == null)
282f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 1000;
283f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
284f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (candidate.configKey(true).equals(currentNetwork.configKey(true))) {
285f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return -1;
286f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
287f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
288f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = compareWifiConfigurations(currentNetwork, candidate);
289f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
290f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order > 0) {
291f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //ascending: currentNetwork < candidate
292f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 10; //will try switch over to the candidate
293f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
294f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
295f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return 0;
296f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
297f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
298ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    /**
299ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * update the network history fields fo that configuration
300ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if userTriggered, we mark the configuration as "non selfAdded" since the user has seen it
301ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * and took over management
302ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if it is a "connect", remember which network were there at the point of the connect, so
303ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * as those networks get a relative lower score than the selected configuration
30462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle     *
305ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param netId
306ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param userTriggered : if the update come from WiFiManager
307ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param connect : if the update includes a connect
308117be607246604e875de62aa8cdd99700b77a2b4vandwalle     **/
30962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle    public void updateConfigurationHistory(int netId, boolean userTriggered, boolean connect) {
310f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration selected = mWifiConfigStore.getWifiConfiguration(netId);
311f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (selected == null) {
312f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return;
313f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
314f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
315e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        if (selected.SSID == null) {
316e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            return;
317e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        }
318e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
31962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        if (userTriggered) {
320ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            // reenable autojoin for this network,
32162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            // since the user want to connect to this configuration
32227355a942653264388e909a4276196ee63e57811vandwalle            selected.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
32362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            selected.selfAdded = false;
32462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        }
325f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
326992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (DBG && userTriggered) {
327f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (selected.connectChoices != null) {
328ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
329f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + Integer.toString(netId) + " now: "
330992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(selected.connectChoices.size())
331992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
332f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
333ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
334992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(netId)
335992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
336f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
337f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
338f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
339ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (connect && userTriggered) {
340ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            boolean found = false;
34162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            List<WifiConfiguration> networks =
34262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    mWifiConfigStore.getRecentConfiguredNetworks(12000, false);
34362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            if (networks != null) {
34462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                for (WifiConfiguration config : networks) {
345992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    if (DBG) {
346992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        logDbg("updateConfigurationHistory got " + config.SSID + " nid="
347992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                                + Integer.toString(config.networkId));
348992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    }
349f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
35062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (selected.configKey(true).equals(config.configKey(true))) {
351ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        found = true;
35262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        continue;
35362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
354f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
35562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    int rssi = WifiConfiguration.INVALID_RSSI;
35662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (config.visibility != null) {
35762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        rssi = config.visibility.rssi5;
35862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        if (config.visibility.rssi24 > rssi)
35962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                            rssi = config.visibility.rssi24;
36062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
36162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (rssi < -80) {
36262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        continue;
36362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
364f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
365ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    //the selected configuration was preferred over a recently seen config
366ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    //hence remember the user's choice:
367ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    //add the recently seen config to the selected's connectChoices array
368ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
369ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    if (selected.connectChoices == null) {
370ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        selected.connectChoices = new HashMap<String, Integer>();
371ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    }
372ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
373ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    logDbg("updateConfigurationHistory add a choice " + selected.configKey(true)
3740888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                            + " over " + config.configKey(true)
375992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                            + " RSSI " + Integer.toString(rssi));
376cf5b8eb8a08c45bd4a82f1f4bb789c8a1b08744fvandwalle
3770888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                    //add the visible config to the selected's connect choice list
37862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    selected.connectChoices.put(config.configKey(true), rssi);
379f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
38062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (config.connectChoices != null) {
381ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        if (VDBG) {
382ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                            logDbg("updateConfigurationHistory will remove "
38362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                    + selected.configKey(true) + " from " + config.configKey(true));
384ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        }
3850888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        //remove the selected from the recently seen config's connectChoice list
38662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        config.connectChoices.remove(selected.configKey(true));
3870888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle
3880888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        if (selected.linkedConfigurations != null) {
3890888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           //remove the selected's linked configuration from the
3900888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           //recently seen config's connectChoice list
3910888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           for (String key : selected.linkedConfigurations.keySet()) {
3920888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                               config.connectChoices.remove(key);
3930888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           }
3940888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        }
39562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
396ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                }
397ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                if (found == false) {
398ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     // log an error for now but do something stringer later
399ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     // we will need a new scan before attempting to connect to this
400ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     // configuration anyhow and thus we can process the scan results then
401ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     logDbg("updateConfigurationHistory try to connect to an old network!! : "
402ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                             + selected.configKey());
40362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
404f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
40562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                if (selected.connectChoices != null) {
40662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (VDBG)
407ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        logDbg("updateConfigurationHistory " + Integer.toString(netId)
40862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                + " now: " + Integer.toString(selected.connectChoices.size()));
40962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
410f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
411f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
412992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle
413992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        //TODO: write only if something changed
414992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (userTriggered || connect) {
415992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle            mWifiConfigStore.writeKnownNetworkHistory();
416992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        }
417f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
418f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
419f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void printChoices(WifiConfiguration config) {
420f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int num = 0;
421f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (config.connectChoices!= null) {
422f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            num = config.connectChoices.size();
423f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
424f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
425f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        logDbg("printChoices " + config.SSID + " num choices: " + Integer.toString(num));
426f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (config.connectChoices!= null) {
427f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            for (String key : config.connectChoices.keySet()) {
428f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                logDbg("                 " + key);
429f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
430f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
431f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
432f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
433f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    boolean hasConnectChoice(WifiConfiguration source, WifiConfiguration target) {
434f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        boolean found = false;
435f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (source == null)
436f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return false;
437f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (target == null)
438f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return false;
439f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
440f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (source.connectChoices != null) {
441f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ( source.connectChoices.get(target.configKey(true)) != null) {
442f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                found = true;
443f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
444f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
445f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
446f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (source.linkedConfigurations != null) {
447f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            for (String key : source.linkedConfigurations.keySet()) {
448f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(key);
449f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (config != null) {
450f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (config.connectChoices != null) {
451f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        if (config.connectChoices.get(target.configKey(true)) != null) {
452f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            found = true;
453f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        }
454f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
455f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
456f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
457f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
458f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return found;
459f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
460f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
461f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    int compareWifiConfigurationsRSSI(WifiConfiguration a, WifiConfiguration b) {
462f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
463f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int boost5 = 25;
464f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
465f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility astatus = a.visibility;
466f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility bstatus = b.visibility;
467f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (astatus == null || bstatus == null) {
468453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            //error -> cant happen, need to throw en exception
469f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("compareWifiConfigurations NULL band status!");
470f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 0;
471f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
472453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if ((astatus.rssi5 > -70) && (bstatus.rssi5 == WifiConfiguration.INVALID_RSSI)
473f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                && ((astatus.rssi5+boost5) > (bstatus.rssi24))) {
474f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //a is seen on 5GHz with good RSSI, greater rssi than b
475f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //a is of higher priority - descending
476f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            order = -1;
477453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        } else if ((bstatus.rssi5 > -70) && (astatus.rssi5 == WifiConfiguration.INVALID_RSSI)
478f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                && ((bstatus.rssi5+boost5) > (bstatus.rssi24))) {
479f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //b is seen on 5GHz with good RSSI, greater rssi than a
480f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //a is of lower priority - ascending
481f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            order = 1;
482f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
483f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
484f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
485f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
486f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    int compareWifiConfigurations(WifiConfiguration a, WifiConfiguration b) {
487f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
488117be607246604e875de62aa8cdd99700b77a2b4vandwalle        String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
489f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        boolean linked = false;
490f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
491453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if ((a.linkedConfigurations != null) && (b.linkedConfigurations != null)
492453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (a.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)
493453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (b.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)) {
494f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((a.linkedConfigurations.get(b.configKey(true))!= null)
495f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    && (b.linkedConfigurations.get(a.configKey(true))!= null)) {
496f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                linked = true;
497f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
498f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
499f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
500f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (a.ephemeral && b.ephemeral == false) {
501f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
502453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("compareWifiConfigurations ephemeral and prefers " + b.configKey()
503453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + a.configKey());
504f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
505f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 1; //b is of higher priority - ascending
506f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
507f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (b.ephemeral && a.ephemeral == false) {
508f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
509453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("compareWifiConfigurations ephemeral and prefers " +a.configKey()
510453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey());
511f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
512f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return -1; //a is of higher priority - descending
513f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
514f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
515f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int boost5 = 25;
516453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        //apply Hysteresis: boost the RSSI value of the currently connected configuration
517453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        int aRssiBoost = 0;
518453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        int bRssiBoost = 0;
519453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if (null != mCurrentConfigurationKey) {
520453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            if (a.configKey().equals(mCurrentConfigurationKey)) {
521453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                aRssiBoost += 10;
522453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            } else if (b.configKey().equals(mCurrentConfigurationKey)) {
523453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                bRssiBoost += 10;
524453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            }
525453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        }
526f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (linked) {
527f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            // then we try prefer 5GHz, and try to ignore user's choice
528f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            WifiConfiguration.Visibility astatus = a.visibility;
529f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            WifiConfiguration.Visibility bstatus = b.visibility;
530f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (astatus == null || bstatus == null) {
531f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                //error
532f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                logDbg("compareWifiConfigurations NULL band status!");
533f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                return 0;
534f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
535f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
536f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG)  {
537f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                logDbg("compareWifiConfigurations linked: " + Integer.toString(astatus.rssi5)
538f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + "," + Integer.toString(astatus.rssi24) + "   "
539f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + Integer.toString(bstatus.rssi5) + ","
540f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + Integer.toString(bstatus.rssi24));
541f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
542f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
543453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            if ((astatus.rssi5 > -70) && (bstatus.rssi5 <= WifiConfiguration.INVALID_RSSI)
544453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    && (astatus.rssi5+boost5+aRssiBoost) > (bstatus.rssi24+bRssiBoost)) {
545453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    //in this case: a has 5GHz and b doesn't have 5GHz
546453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    //compare a's 5GHz RSSI to b's 5GHz RSSI
547453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
548f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    //a is seen on 5GHz with good RSSI, greater rssi than b
549f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    //a is of higher priority - descending
550f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    order = -10;
551f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
552f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG) {
553453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("compareWifiConfigurations linked and prefers " + a.configKey()
554453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + " over " + b.configKey()
555f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            + " due to 5GHz RSSI " + Integer.toString(astatus.rssi5)
556f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            + " over: 5=" + Integer.toString(bstatus.rssi5)
557f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            + ", 2.4=" + Integer.toString(bstatus.rssi5));
558f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
559453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            } else if ((bstatus.rssi5 > -70) && (astatus.rssi5 <= WifiConfiguration.INVALID_RSSI)
560453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    && ((bstatus.rssi5+boost5+bRssiBoost) > (astatus.rssi24+aRssiBoost))) {
561453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    //in this case: b has 5GHz and a doesn't have 5GHz
562453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
563f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    //b is seen on 5GHz with good RSSI, greater rssi than a
564f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    //a is of lower priority - ascending
565f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)   {
566453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("compareWifiConfigurations linked and prefers " + b.configKey()
567453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + " over " + a.configKey() + " due to 5GHz RSSI "
568f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            + Integer.toString(astatus.rssi5) + " over: 5="
569f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            + Integer.toString(bstatus.rssi5) + ", 2.4="
570f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            + Integer.toString(bstatus.rssi5));
571f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
572f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                order = 10;
573453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            } else {
574453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                //TODO: handle cases where configurations are dual band
575f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
576f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
577ede1310be531a84faa08f02c3fd243448dd936ddvandwalle
578ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        //compare by user's choice.
579f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (hasConnectChoice(a, b)) {
580f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //a is of higher priority - descending
581f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            order = order -2;
582f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG)   {
583453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("compareWifiConfigurations prefers -2 " + a.configKey()
584453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey()
585ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        + " due to user choice order -> " + Integer.toString(order));
586f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
587f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
588f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
589f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (hasConnectChoice(b, a)) {
590f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //a is of lower priority - ascending
591f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            order = order + 2;
592f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG)   {
593453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("compareWifiConfigurations prefers +2 " + b.configKey() + " over "
594453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + a.configKey() + " due to user choice order ->" + Integer.toString(order));
595f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
596f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
597f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
598ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        //TODO count the number of association rejection
599ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        // and use this to adjust the order by more than +/- 3
600ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        if ((a.status == WifiConfiguration.Status.DISABLED)
601ede1310be531a84faa08f02c3fd243448dd936ddvandwalle                && (a.disableReason == WifiConfiguration.DISABLED_ASSOCIATION_REJECT)) {
602ede1310be531a84faa08f02c3fd243448dd936ddvandwalle            //a is of lower priority - ascending
603ede1310be531a84faa08f02c3fd243448dd936ddvandwalle            //lower the comparison score a bit
604ede1310be531a84faa08f02c3fd243448dd936ddvandwalle            order = order +3;
605ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        }
606ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        if ((b.status == WifiConfiguration.Status.DISABLED)
607ede1310be531a84faa08f02c3fd243448dd936ddvandwalle                && (b.disableReason == WifiConfiguration.DISABLED_ASSOCIATION_REJECT)) {
608ede1310be531a84faa08f02c3fd243448dd936ddvandwalle            //a is of higher priority - descending
609ede1310be531a84faa08f02c3fd243448dd936ddvandwalle            //lower the comparison score a bit
610ede1310be531a84faa08f02c3fd243448dd936ddvandwalle            order = order -3;
611ede1310be531a84faa08f02c3fd243448dd936ddvandwalle        }
612ede1310be531a84faa08f02c3fd243448dd936ddvandwalle
613ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if ((lastSelectedConfiguration != null)
614ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                && a.configKey().equals(lastSelectedConfiguration)) {
615ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            // a is the last selected configuration, so keep it above connect choices
616ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            //by giving a -4 (whereas connect choice preference gives +2)
617ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            order = order - 4;
618ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            if (VDBG)   {
619453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("compareWifiConfigurations prefers -4 " + a.configKey()
620453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey() + " because a is the last selected -> "
621ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        + Integer.toString(order));
622ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            }
623ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        } else if ((lastSelectedConfiguration != null)
624ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                && b.configKey().equals(lastSelectedConfiguration)) {
625ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            // b is the last selected configuration, so keep it above connect choices
626ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            //by giving a +4 (whereas connect choice preference gives -2)
627ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            order = order + 4;
628ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            if (VDBG)   {
629453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("compareWifiConfigurations prefers +4 " + a.configKey()
630453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey() + " because b is the last selected -> "
631ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        + Integer.toString(order));
632ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            }
633ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        }
634ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
635f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order == 0) {
636f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //we don't know anything - pick the last seen i.e. K behavior
637f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //we should do this only for recently picked configurations
638f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (a.priority > b.priority) {
639f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                //a is of higher priority - descending
640f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)   {
641453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("compareWifiConfigurations prefers -1 " + a.configKey() + " over "
642453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + b.configKey() + " due to priority");
643f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
644f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
645f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                order = -1;
646f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else if (a.priority < b.priority) {
647f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                //a is of lower priority - ascending
648f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)  {
649453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("compareWifiConfigurations prefers +1 " + b.configKey() + " over "
650453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + a.configKey() + " due to priority");
651f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
652f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
653f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle              order = 1;
654f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
655f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                //maybe just look at RSSI or band
656f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)  {
657453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("compareWifiConfigurations prefers +1 " + b.configKey() + " over "
658453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + a.configKey() + " due to nothing");
659f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
660f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
661f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                order = compareWifiConfigurationsRSSI(a, b); //compare RSSI
662f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
663f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
664f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
665f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String sorder = " == ";
666f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order > 0)
667f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " < ";
668f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order < 0)
669f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " > ";
670f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
671f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG)   {
672453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            logDbg("compareWifiConfigurations Done: " + a.configKey() + sorder
673453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    + b.configKey() + " order " + Integer.toString(order));
674f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
675f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
676f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
677f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
678f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
679f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    /* attemptAutoJoin function implement the core of the a network switching algorithm */
680f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void attemptAutoJoin() {
6818c9088d11880553458f09377cc60d6eb7e66747bvandwalle        String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
6828c9088d11880553458f09377cc60d6eb7e66747bvandwalle
68327355a942653264388e909a4276196ee63e57811vandwalle        // reset the currentConfiguration Key, and set it only if WifiStateMachine and
684453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        // supplicant agree
685453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        mCurrentConfigurationKey = null;
686453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        WifiConfiguration currentConfiguration = mWifiStateMachine.getCurrentWifiConfiguration();
687453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
688f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration candidate = null;
689f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
690f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        /* obtain the subset of recently seen networks */
69127355a942653264388e909a4276196ee63e57811vandwalle        List<WifiConfiguration> list = mWifiConfigStore.getRecentConfiguredNetworks(3000, false);
692f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (list == null) {
693f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG)  logDbg("attemptAutoJoin nothing");
694f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return;
695f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
696f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
697f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        /* find the currently connected network: ask the supplicant directly */
698f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String val = mWifiNative.status();
699f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String status[] = val.split("\\r?\\n");
700f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
701f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("attemptAutoJoin() status=" + val + " split="
702f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(status.length));
703f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
704f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
705f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int currentNetId = -1;
706f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (String key : status) {
707f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (key.regionMatches(0, "id=", 0, 3)) {
708f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int idx = 3;
709f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                currentNetId = 0;
710f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                while (idx < key.length()) {
711f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    char c = key.charAt(idx);
712f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
713f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if ((c >= 0x30) && (c <= 0x39)) {
714f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        currentNetId *= 10;
715f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        currentNetId += c - 0x30;
716f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        idx++;
717f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    } else {
718f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        break;
719f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
720f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
721f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
722f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
723ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (DBG) {
724ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            logDbg("attemptAutoJoin() num recent config " + Integer.toString(list.size())
725ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                    + " ---> currentId=" + Integer.toString(currentNetId));
726ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
727f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
728453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if (currentConfiguration != null) {
729453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            if (currentNetId != currentConfiguration.networkId) {
730453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("attemptAutoJoin() ERROR wpa_supplicant out of sync nid="
731453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + Integer.toString(currentNetId) + " WifiStateMachine="
732453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + Integer.toString(currentConfiguration.networkId));
733453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                //I think this can happen due do race conditions, now what to do??
734453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                // -> throw an exception, or,
735453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                // -> dont use the current configuration at all for autojoin
736453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                //and hope that autojoining will kick us out of this state.
737453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                currentConfiguration = null;
738453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            } else {
739453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                mCurrentConfigurationKey = currentConfiguration.configKey();
740453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            }
741453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        }
742453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
743f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        /* select Best Network candidate from known WifiConfigurations */
744f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (WifiConfiguration config : list) {
745f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((config.status == WifiConfiguration.Status.DISABLED)
746f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    && (config.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE)) {
747ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
748ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                    logDbg("attemptAutoJoin skip candidate due to auth failure key "
749ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + config.configKey(true));
750ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
751f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
752f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
753453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
754e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            if (config.SSID == null) {
755e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle                return;
756e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            }
757e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
75827355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
75927355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
760453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                //avoid temporarily disabled networks altogether
761453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                //TODO: implement a better logic which will reenable the network after some time
762ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
763ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                    logDbg("attemptAutoJoin skip candidate due to auto join status "
764ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + Integer.toString(config.autoJoinStatus) + " key "
765ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + config.configKey(true));
766ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
767f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
768f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
769f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
77027355a942653264388e909a4276196ee63e57811vandwalle            //try to unblacklist based on elapsed time
77127355a942653264388e909a4276196ee63e57811vandwalle            if (config.blackListTimestamp > 0) {
77227355a942653264388e909a4276196ee63e57811vandwalle                long now = System.currentTimeMillis();
77327355a942653264388e909a4276196ee63e57811vandwalle                if (now < config.blackListTimestamp) {
77427355a942653264388e909a4276196ee63e57811vandwalle                    //looks like there was a change in the system clock since we black listed, and the
77527355a942653264388e909a4276196ee63e57811vandwalle                    //timestamp is not meaningful anymore, hence lose it.
77627355a942653264388e909a4276196ee63e57811vandwalle                    //this event should be rare enough so that we still want to lose the black list
77727355a942653264388e909a4276196ee63e57811vandwalle                    config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
77827355a942653264388e909a4276196ee63e57811vandwalle                } else {
77927355a942653264388e909a4276196ee63e57811vandwalle                    if ((now - config.blackListTimestamp) > loseBlackListHardMilly) {
78027355a942653264388e909a4276196ee63e57811vandwalle                        //reenable it after 18 hours, i.e. next day
78127355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
78227355a942653264388e909a4276196ee63e57811vandwalle                    } else if ((now - config.blackListTimestamp) > loseBlackListSoftMilly) {
78327355a942653264388e909a4276196ee63e57811vandwalle                        //lose blacklisting due to bad link
78427355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(config.autoJoinStatus - 8);
78527355a942653264388e909a4276196ee63e57811vandwalle                    }
78627355a942653264388e909a4276196ee63e57811vandwalle                }
78727355a942653264388e909a4276196ee63e57811vandwalle            }
78827355a942653264388e909a4276196ee63e57811vandwalle
78927355a942653264388e909a4276196ee63e57811vandwalle            //try to unblacklist based on good visibility
79027355a942653264388e909a4276196ee63e57811vandwalle            if (config.visibility.rssi5 < WifiConfiguration.UNBLACKLIST_THRESHOLD_5_SOFT
79127355a942653264388e909a4276196ee63e57811vandwalle                    && config.visibility.rssi24 < WifiConfiguration.UNBLACKLIST_THRESHOLD_24_SOFT) {
79227355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
79327355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin skip candidate due to auto join status "
79427355a942653264388e909a4276196ee63e57811vandwalle                            + Integer.toString(config.autoJoinStatus) + " key "
79527355a942653264388e909a4276196ee63e57811vandwalle                            + config.configKey(true)
79627355a942653264388e909a4276196ee63e57811vandwalle                            + " rssi=" + config.visibility.rssi24
79727355a942653264388e909a4276196ee63e57811vandwalle                            + ", " + config.visibility.rssi5
79827355a942653264388e909a4276196ee63e57811vandwalle                            + " num=" + config.visibility.num24
79927355a942653264388e909a4276196ee63e57811vandwalle                            + ", " + config.visibility.num5);
80027355a942653264388e909a4276196ee63e57811vandwalle                }
80127355a942653264388e909a4276196ee63e57811vandwalle            } else if (config.visibility.rssi5 < WifiConfiguration.UNBLACKLIST_THRESHOLD_5_HARD
80227355a942653264388e909a4276196ee63e57811vandwalle                    && config.visibility.rssi24 < WifiConfiguration.UNBLACKLIST_THRESHOLD_24_HARD) {
80327355a942653264388e909a4276196ee63e57811vandwalle                // if the network is simply temporary disabled, don't allow reconnect until
80427355a942653264388e909a4276196ee63e57811vandwalle                // rssi becomes good enough
80527355a942653264388e909a4276196ee63e57811vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 1);
80627355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
80727355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped soft -> status="
80827355a942653264388e909a4276196ee63e57811vandwalle                            + config.autoJoinStatus
80927355a942653264388e909a4276196ee63e57811vandwalle                            + ", " + config.visibility.rssi5
81027355a942653264388e909a4276196ee63e57811vandwalle                            + " num=" + config.visibility.num24
81127355a942653264388e909a4276196ee63e57811vandwalle                            + ", " + config.visibility.num5);
81227355a942653264388e909a4276196ee63e57811vandwalle                }
81327355a942653264388e909a4276196ee63e57811vandwalle            } else {
81427355a942653264388e909a4276196ee63e57811vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 2);
81527355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
81627355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped hard -> status="
81727355a942653264388e909a4276196ee63e57811vandwalle                            + config.autoJoinStatus
81827355a942653264388e909a4276196ee63e57811vandwalle                            + ", " + config.visibility.rssi5
81927355a942653264388e909a4276196ee63e57811vandwalle                            + " num=" + config.visibility.num24
82027355a942653264388e909a4276196ee63e57811vandwalle                            + ", " + config.visibility.num5);
82127355a942653264388e909a4276196ee63e57811vandwalle                }
82227355a942653264388e909a4276196ee63e57811vandwalle            }
82327355a942653264388e909a4276196ee63e57811vandwalle
82427355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
82527355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED) {
82627355a942653264388e909a4276196ee63e57811vandwalle                //network is blacklisted, skip
82727355a942653264388e909a4276196ee63e57811vandwalle                continue;
82827355a942653264388e909a4276196ee63e57811vandwalle            }
829f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (config.networkId == currentNetId) {
830ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
83121bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    logDbg("attemptAutoJoin skip current candidate  "
83221bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                            + Integer.toString(currentNetId)
833ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + " key " + config.configKey(true));
834ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
835f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
836f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
837f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
83821bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle            if (lastSelectedConfiguration == null ||
83921bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    !config.configKey().equals(lastSelectedConfiguration)) {
8408c9088d11880553458f09377cc60d6eb7e66747bvandwalle                //don't try to autojoin a network that is too far
8418c9088d11880553458f09377cc60d6eb7e66747bvandwalle                if (config.visibility == null) {
8428c9088d11880553458f09377cc60d6eb7e66747bvandwalle                    continue;
8438c9088d11880553458f09377cc60d6eb7e66747bvandwalle                }
84427355a942653264388e909a4276196ee63e57811vandwalle                if (config.visibility.rssi5 < WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_5
84527355a942653264388e909a4276196ee63e57811vandwalle                        && config.visibility.rssi24 < WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_24) {
8468c9088d11880553458f09377cc60d6eb7e66747bvandwalle                    continue;
8478c9088d11880553458f09377cc60d6eb7e66747bvandwalle                }
8488c9088d11880553458f09377cc60d6eb7e66747bvandwalle            }
8498c9088d11880553458f09377cc60d6eb7e66747bvandwalle
850ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            if (DBG) {
851ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                logDbg("attemptAutoJoin trying candidate id=" + config.networkId + " "
852ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                        + config.SSID + " key " + config.configKey(true));
853ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            }
854f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
855f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate == null) {
856f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                candidate = config;
857f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
858f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)  {
859453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("attemptAutoJoin will compare candidate  " + candidate.configKey()
860453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + " with " + config.configKey() + " key " + config.configKey(true));
861f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
862f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
863f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int order = compareWifiConfigurations(candidate, config);
864f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (order > 0) {
865f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    //ascending : candidate < config
866f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    candidate = config;
867f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
868f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
869f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
870f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
871f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        /* now, go thru scan result to try finding a better Herrevad network */
872f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (mNetworkScoreCache != null) {
873f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi5 = WifiConfiguration.INVALID_RSSI;
874f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi24 = WifiConfiguration.INVALID_RSSI;
875f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            WifiConfiguration.Visibility visibility;
876f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate != null) {
877f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi5 = candidate.visibility.rssi5;
878f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi24 = candidate.visibility.rssi24;
879f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
880f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
881f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //get current date
882f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            Date now = new Date();
883f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            long now_ms = now.getTime();
884f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
885f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (rssi5 < -60 && rssi24 < -70) {
886f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                for (ScanResult result : scanResultCache.values()) {
887f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if ((now_ms - result.seen) < 3000) {
888f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        int score = mNetworkScoreCache.getNetworkScore(result);
889f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        if (score > 0) {
890f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            // try any arbitrary formula for now, adding apple and oranges,
891f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            // i.e. adding network score and "dBm over noise"
892f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                           if (result.frequency < 4000) {
893f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                if ((result.level + score) > (rssi24 -40)) {
894f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    // force it as open, TBD should we otherwise verify that this
895f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    // BSSID only supports open??
896f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    result.capabilities = "";
897f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
898f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    //switch to this scan result
899f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    candidate =
90021bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                                           mWifiConfigStore.wifiConfigurationFromScanResult(result);
901f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    candidate.ephemeral = true;
902f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                }
903f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                           } else {
904f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                if ((result.level + score) > (rssi5 -30)) {
905f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    // force it as open, TBD should we otherwise verify that this
906f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    // BSSID only supports open??
907f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    result.capabilities = "";
908f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
909f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    //switch to this scan result
910f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    candidate =
91121bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                                           mWifiConfigStore.wifiConfigurationFromScanResult(result);
912f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    candidate.ephemeral = true;
913f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                }
914f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                           }
915f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        }
916f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
917f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
918f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
919f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
920f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (candidate != null) {
921453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        /* if candidate is found, check the state of the connection so as
922453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        to decide if we should be acting on this candidate and switching over */
923f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int networkDelta = compareNetwork(candidate);
924ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            if (DBG && (networkDelta > 0)) {
925453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("attemptAutoJoin did find candidate " + candidate.configKey()
926f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + " for delta " + Integer.toString(networkDelta));
927ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            }
928f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            /* ASK traffic poller permission to switch:
929f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                for instance,
930f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if user is currently streaming voice traffic,
931f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                then don’t switch regardless of the delta */
932f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
933f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (mWifiTrafficPoller.shouldSwitchNetwork(networkDelta)) {
934f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (mStaStaSupported) {
935453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("mStaStaSupported --> error do nothing now ");
936f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                } else {
937f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (DBG) {
938453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        logDbg("AutoJoin auto connect with netId "
939f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                + Integer.toString(candidate.networkId)
940453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                                + " to " + candidate.configKey());
941f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
942f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT,
943f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            candidate.networkId);
944f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
945f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
946f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
947f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) logDbg("Done attemptAutoJoin");
948f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
949f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle}
950f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
951