blob: 09e74720a645d03e05c5d06104c7e1604216e52b [file] [log] [blame]
John Spurlock7f8f22a2014-07-02 18:54:17 -04001/*
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.systemui.statusbar.policy;
18
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.net.wifi.ScanResult;
24import android.net.wifi.WifiConfiguration;
25import android.net.wifi.WifiInfo;
26import android.net.wifi.WifiManager;
27import android.net.wifi.WifiManager.ActionListener;
28import android.text.TextUtils;
29import android.util.ArrayMap;
30import android.util.ArraySet;
31import android.util.Log;
32
33import com.android.systemui.R;
34import com.android.systemui.statusbar.policy.NetworkController.AccessPoint;
35import com.android.systemui.statusbar.policy.NetworkController.AccessPointCallback;
36
37import java.util.ArrayList;
38import java.util.Collections;
39import java.util.Comparator;
40import java.util.List;
41
42public class WifiAccessPointController {
43 private static final String TAG = "WifiAccessPointController";
44 private static final boolean DEBUG = false;
45
46 private static final int[] ICONS = {
47 R.drawable.ic_qs_wifi_0,
48 R.drawable.ic_qs_wifi_full_1,
49 R.drawable.ic_qs_wifi_full_2,
50 R.drawable.ic_qs_wifi_full_3,
51 R.drawable.ic_qs_wifi_full_4,
52 };
53
54 private final Context mContext;
55 private final ArrayList<AccessPointCallback> mCallbacks = new ArrayList<AccessPointCallback>();
56 private final WifiManager mWifiManager;
57 private final Receiver mReceiver = new Receiver();
58
59 private boolean mScanning;
60
61 public WifiAccessPointController(Context context) {
62 mContext = context;
63 mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
64 }
65
66 public void addCallback(AccessPointCallback callback) {
67 if (callback == null || mCallbacks.contains(callback)) return;
68 if (DEBUG) Log.d(TAG, "addCallback " + callback);
69 mCallbacks.add(callback);
70 mReceiver.setListening(!mCallbacks.isEmpty());
71 }
72
73 public void removeCallback(AccessPointCallback callback) {
74 if (callback == null) return;
75 if (DEBUG) Log.d(TAG, "removeCallback " + callback);
76 mCallbacks.remove(callback);
77 mReceiver.setListening(!mCallbacks.isEmpty());
78 }
79
80 public void scan() {
81 if (mScanning) return;
82 if (DEBUG) Log.d(TAG, "scan!");
83 mScanning = mWifiManager.startScan();
84 }
85
86 public void connect(AccessPoint ap) {
87 if (ap == null || ap.networkId < 0) return;
88 if (DEBUG) Log.d(TAG, "connect networkId=" + ap.networkId);
89 mWifiManager.connect(ap.networkId, new ActionListener() {
90 @Override
91 public void onSuccess() {
92 if (DEBUG) Log.d(TAG, "connect success");
93 }
94
95 @Override
96 public void onFailure(int reason) {
97 if (DEBUG) Log.d(TAG, "connect failure reason=" + reason);
98 }
99 });
100 }
101
102 private void fireCallback(AccessPoint[] aps) {
103 for (AccessPointCallback callback : mCallbacks) {
104 callback.onAccessPointsChanged(aps);
105 }
106 }
107
108 private static String trimDoubleQuotes(String v) {
109 return v != null && v.length() >= 2 && v.charAt(0) == '\"'
110 && v.charAt(v.length() - 1) == '\"' ? v.substring(1, v.length() - 1) : v;
111 }
112
113 private int getConnectedNetworkId() {
114 final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
115 return wifiInfo != null ? wifiInfo.getNetworkId() : AccessPoint.NO_NETWORK;
116 }
117
118 private ArrayMap<String, WifiConfiguration> getConfiguredNetworksBySsid() {
119 final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
120 if (configs == null || configs.size() == 0) return ArrayMap.EMPTY;
121 final ArrayMap<String, WifiConfiguration> rt = new ArrayMap<String, WifiConfiguration>();
122 for (WifiConfiguration config : configs) {
123 rt.put(trimDoubleQuotes(config.SSID), config);
124 }
125 return rt;
126 }
127
128 private void updateAccessPoints() {
129 final int connectedNetworkId = getConnectedNetworkId();
130 if (DEBUG) Log.d(TAG, "connectedNetworkId: " + connectedNetworkId);
131 final List<ScanResult> scanResults = mWifiManager.getScanResults();
132 final ArrayMap<String, WifiConfiguration> configured = getConfiguredNetworksBySsid();
133 if (DEBUG) Log.d(TAG, "scanResults: " + scanResults);
134 final List<AccessPoint> aps = new ArrayList<AccessPoint>(scanResults.size());
135 final ArraySet<String> ssids = new ArraySet<String>();
136 for (ScanResult scanResult : scanResults) {
137 final String ssid = scanResult.SSID;
138 if (TextUtils.isEmpty(ssid) || ssids.contains(ssid)) continue;
139 if (!configured.containsKey(ssid)) continue;
140 ssids.add(ssid);
141 final WifiConfiguration config = configured.get(ssid);
142 final int level = WifiManager.calculateSignalLevel(scanResult.level, ICONS.length);
143 final AccessPoint ap = new AccessPoint();
144 ap.networkId = config != null ? config.networkId : AccessPoint.NO_NETWORK;
145 ap.ssid = ssid;
146 ap.iconId = ICONS[level];
147 ap.isConnected = ap.networkId != AccessPoint.NO_NETWORK
148 && ap.networkId == connectedNetworkId;
149 ap.level = level;
150 aps.add(ap);
151 }
152 Collections.sort(aps, mByStrength);
153 fireCallback(aps.toArray(new AccessPoint[aps.size()]));
154 }
155
156 private final Comparator<AccessPoint> mByStrength = new Comparator<AccessPoint> () {
157 @Override
158 public int compare(AccessPoint lhs, AccessPoint rhs) {
159 return -Integer.compare(score(lhs), score(rhs));
160 }
161
162 private int score(AccessPoint ap) {
163 return ap.level + (ap.isConnected ? 10 : 0);
164 }
165 };
166
167 private final class Receiver extends BroadcastReceiver {
168 private boolean mRegistered;
169
170 public void setListening(boolean listening) {
171 if (listening && !mRegistered) {
172 if (DEBUG) Log.d(TAG, "Registering receiver");
173 final IntentFilter filter = new IntentFilter();
174 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
175 filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
176 filter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
177 filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
178 filter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
179 filter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
180 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
181 filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
182 mContext.registerReceiver(this, filter);
183 mRegistered = true;
184 } else if (!listening && mRegistered) {
185 if (DEBUG) Log.d(TAG, "Unregistering receiver");
186 mContext.unregisterReceiver(this);
187 mRegistered = false;
188 }
189 }
190
191 @Override
192 public void onReceive(Context context, Intent intent) {
193 if (DEBUG) Log.d(TAG, "onReceive " + intent.getAction());
194 if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) {
195 updateAccessPoints();
196 mScanning = false;
197 }
198 }
199 }
200}