1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wifi;
18
19import android.Manifest.permission;
20import android.content.Context;
21import android.net.INetworkScoreCache;
22import android.net.NetworkKey;
23import android.net.ScoredNetwork;
24import android.net.wifi.ScanResult;
25import android.net.wifi.WifiManager;
26import android.util.Log;
27
28import java.io.FileDescriptor;
29import java.io.PrintWriter;
30import java.util.HashMap;
31import java.util.List;
32import java.util.Map;
33
34public class WifiNetworkScoreCache extends INetworkScoreCache.Stub
35 {
36
37    // A Network scorer returns a score in the range [-127, +127]
38    public static int INVALID_NETWORK_SCORE = 100000;
39
40    private static String TAG = "WifiNetworkScoreCache";
41    private boolean DBG = true;
42    private final Context mContext;
43
44    // The key is of the form "<ssid>"<bssid>
45    // TODO: What about SSIDs that can't be encoded as UTF-8?
46    private final Map<String, ScoredNetwork> mNetworkCache;
47
48    public WifiNetworkScoreCache(Context context) {
49        mContext = context;
50        mNetworkCache = new HashMap<String, ScoredNetwork>();
51    }
52
53     @Override public final void updateScores(List<android.net.ScoredNetwork> networks) {
54        if (networks == null) {
55            return;
56        }
57        Log.e(TAG, "updateScores list size=" + networks.size());
58
59        synchronized(mNetworkCache) {
60            for (ScoredNetwork network : networks) {
61                String networkKey = buildNetworkKey(network);
62                if (networkKey == null) continue;
63                mNetworkCache.put(networkKey, network);
64            }
65        }
66     }
67
68     @Override public final void clearScores() {
69         synchronized (mNetworkCache) {
70             mNetworkCache.clear();
71         }
72     }
73
74    public boolean isScoredNetwork(ScanResult result) {
75        String key = buildNetworkKey(result);
76        if (key == null) return false;
77
78        //find it
79        synchronized(mNetworkCache) {
80            ScoredNetwork network = mNetworkCache.get(key);
81            if (network != null) {
82                return true;
83            }
84        }
85        return false;
86    }
87
88    public int getNetworkScore(ScanResult result) {
89
90        int score = INVALID_NETWORK_SCORE;
91
92        String key = buildNetworkKey(result);
93        if (key == null) return score;
94
95        //find it
96        synchronized(mNetworkCache) {
97            ScoredNetwork network = mNetworkCache.get(key);
98            if (network != null && network.rssiCurve != null) {
99                score = network.rssiCurve.lookupScore(result.level);
100                if (DBG) {
101                    Log.e(TAG, "getNetworkScore found scored network " + key
102                            + " score " + Integer.toString(score)
103                            + " RSSI " + result.level);
104                }
105            }
106        }
107        return score;
108    }
109
110    public int getNetworkScore(ScanResult result, int rssiBoost) {
111
112        int score = INVALID_NETWORK_SCORE;
113
114        String key = buildNetworkKey(result);
115        if (key == null) return score;
116
117        //find it
118        synchronized(mNetworkCache) {
119            ScoredNetwork network = mNetworkCache.get(key);
120            if (network != null && network.rssiCurve != null) {
121                score = network.rssiCurve.lookupScore(result.level + rssiBoost);
122                if (DBG) {
123                    Log.e(TAG, "getNetworkScore found scored network " + key
124                            + " score " + Integer.toString(score)
125                            + " RSSI " + result.level
126                            + " boost " + rssiBoost);
127                }
128            }
129        }
130        return score;
131    }
132
133     private String buildNetworkKey(ScoredNetwork network) {
134        if (network.networkKey == null) return null;
135        if (network.networkKey.wifiKey == null) return null;
136        if (network.networkKey.type == NetworkKey.TYPE_WIFI) {
137            String key = network.networkKey.wifiKey.ssid;
138            if (key == null) return null;
139            if (network.networkKey.wifiKey.bssid != null) {
140                key = key + network.networkKey.wifiKey.bssid;
141            }
142            return key;
143        }
144        return null;
145    }
146
147    private String buildNetworkKey(ScanResult result) {
148        if (result.SSID == null) {
149            return null;
150        }
151        StringBuilder key = new StringBuilder("\"");
152        key.append(result.SSID);
153        key.append("\"");
154        if (result.BSSID != null) {
155            key.append(result.BSSID);
156        }
157        return key.toString();
158    }
159
160    @Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
161        mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
162        writer.println("WifiNetworkScoreCache");
163        writer.println("  All score curves:");
164        for (Map.Entry<String, ScoredNetwork> entry : mNetworkCache.entrySet()) {
165            writer.println("    " + entry.getKey() + ": " + entry.getValue().rssiCurve);
166        }
167        writer.println("  Current network scores:");
168        WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
169        for (ScanResult scanResult : wifiManager.getScanResults()) {
170            writer.println("    " + buildNetworkKey(scanResult) + ": " + getNetworkScore(scanResult));
171        }
172    }
173
174}
175