• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 
17 package com.android.settings.wifi;
18 
19 import android.content.Context;
20 import android.net.NetworkInfo.DetailedState;
21 import android.net.wifi.ScanResult;
22 import android.net.wifi.WifiConfiguration;
23 import android.net.wifi.WifiConfiguration.KeyMgmt;
24 import android.net.wifi.WifiInfo;
25 import android.net.wifi.WifiManager;
26 import android.os.Bundle;
27 import android.preference.Preference;
28 import android.util.Log;
29 import android.view.View;
30 import android.widget.ImageView;
31 
32 import com.android.settings.R;
33 
34 class AccessPoint extends Preference {
35     static final String TAG = "Settings.AccessPoint";
36 
37     private static final String KEY_DETAILEDSTATE = "key_detailedstate";
38     private static final String KEY_WIFIINFO = "key_wifiinfo";
39     private static final String KEY_SCANRESULT = "key_scanresult";
40     private static final String KEY_CONFIG = "key_config";
41 
42     private static final int[] STATE_SECURED = {
43         R.attr.state_encrypted
44     };
45     private static final int[] STATE_NONE = {};
46 
47     /** These values are matched in string arrays -- changes must be kept in sync */
48     static final int SECURITY_NONE = 0;
49     static final int SECURITY_WEP = 1;
50     static final int SECURITY_PSK = 2;
51     static final int SECURITY_EAP = 3;
52 
53     enum PskType {
54         UNKNOWN,
55         WPA,
56         WPA2,
57         WPA_WPA2
58     }
59 
60     String ssid;
61     String bssid;
62     int security;
63     int networkId;
64     boolean wpsAvailable = false;
65 
66     PskType pskType = PskType.UNKNOWN;
67 
68     private WifiConfiguration mConfig;
69     /* package */ScanResult mScanResult;
70 
71     private int mRssi;
72     private WifiInfo mInfo;
73     private DetailedState mState;
74 
getSecurity(WifiConfiguration config)75     static int getSecurity(WifiConfiguration config) {
76         if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
77             return SECURITY_PSK;
78         }
79         if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
80                 config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
81             return SECURITY_EAP;
82         }
83         return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE;
84     }
85 
getSecurity(ScanResult result)86     private static int getSecurity(ScanResult result) {
87         if (result.capabilities.contains("WEP")) {
88             return SECURITY_WEP;
89         } else if (result.capabilities.contains("PSK")) {
90             return SECURITY_PSK;
91         } else if (result.capabilities.contains("EAP")) {
92             return SECURITY_EAP;
93         }
94         return SECURITY_NONE;
95     }
96 
getSecurityString(boolean concise)97     public String getSecurityString(boolean concise) {
98         Context context = getContext();
99         switch(security) {
100             case SECURITY_EAP:
101                 return concise ? context.getString(R.string.wifi_security_short_eap) :
102                     context.getString(R.string.wifi_security_eap);
103             case SECURITY_PSK:
104                 switch (pskType) {
105                     case WPA:
106                         return concise ? context.getString(R.string.wifi_security_short_wpa) :
107                             context.getString(R.string.wifi_security_wpa);
108                     case WPA2:
109                         return concise ? context.getString(R.string.wifi_security_short_wpa2) :
110                             context.getString(R.string.wifi_security_wpa2);
111                     case WPA_WPA2:
112                         return concise ? context.getString(R.string.wifi_security_short_wpa_wpa2) :
113                             context.getString(R.string.wifi_security_wpa_wpa2);
114                     case UNKNOWN:
115                     default:
116                         return concise ? context.getString(R.string.wifi_security_short_psk_generic)
117                                 : context.getString(R.string.wifi_security_psk_generic);
118                 }
119             case SECURITY_WEP:
120                 return concise ? context.getString(R.string.wifi_security_short_wep) :
121                     context.getString(R.string.wifi_security_wep);
122             case SECURITY_NONE:
123             default:
124                 return concise ? "" : context.getString(R.string.wifi_security_none);
125         }
126     }
127 
getPskType(ScanResult result)128     private static PskType getPskType(ScanResult result) {
129         boolean wpa = result.capabilities.contains("WPA-PSK");
130         boolean wpa2 = result.capabilities.contains("WPA2-PSK");
131         if (wpa2 && wpa) {
132             return PskType.WPA_WPA2;
133         } else if (wpa2) {
134             return PskType.WPA2;
135         } else if (wpa) {
136             return PskType.WPA;
137         } else {
138             Log.w(TAG, "Received abnormal flag string: " + result.capabilities);
139             return PskType.UNKNOWN;
140         }
141     }
142 
AccessPoint(Context context, WifiConfiguration config)143     AccessPoint(Context context, WifiConfiguration config) {
144         super(context);
145         setWidgetLayoutResource(R.layout.preference_widget_wifi_signal);
146         loadConfig(config);
147         refresh();
148     }
149 
AccessPoint(Context context, ScanResult result)150     AccessPoint(Context context, ScanResult result) {
151         super(context);
152         setWidgetLayoutResource(R.layout.preference_widget_wifi_signal);
153         loadResult(result);
154         refresh();
155     }
156 
AccessPoint(Context context, Bundle savedState)157     AccessPoint(Context context, Bundle savedState) {
158         super(context);
159         setWidgetLayoutResource(R.layout.preference_widget_wifi_signal);
160 
161         mConfig = savedState.getParcelable(KEY_CONFIG);
162         if (mConfig != null) {
163             loadConfig(mConfig);
164         }
165         mScanResult = (ScanResult) savedState.getParcelable(KEY_SCANRESULT);
166         if (mScanResult != null) {
167             loadResult(mScanResult);
168         }
169         mInfo = (WifiInfo) savedState.getParcelable(KEY_WIFIINFO);
170         if (savedState.containsKey(KEY_DETAILEDSTATE)) {
171             mState = DetailedState.valueOf(savedState.getString(KEY_DETAILEDSTATE));
172         }
173         update(mInfo, mState);
174     }
175 
saveWifiState(Bundle savedState)176     public void saveWifiState(Bundle savedState) {
177         savedState.putParcelable(KEY_CONFIG, mConfig);
178         savedState.putParcelable(KEY_SCANRESULT, mScanResult);
179         savedState.putParcelable(KEY_WIFIINFO, mInfo);
180         if (mState != null) {
181             savedState.putString(KEY_DETAILEDSTATE, mState.toString());
182         }
183     }
184 
loadConfig(WifiConfiguration config)185     private void loadConfig(WifiConfiguration config) {
186         ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
187         bssid = config.BSSID;
188         security = getSecurity(config);
189         networkId = config.networkId;
190         mRssi = Integer.MAX_VALUE;
191         mConfig = config;
192     }
193 
loadResult(ScanResult result)194     private void loadResult(ScanResult result) {
195         ssid = result.SSID;
196         bssid = result.BSSID;
197         security = getSecurity(result);
198         wpsAvailable = security != SECURITY_EAP && result.capabilities.contains("WPS");
199         if (security == SECURITY_PSK)
200             pskType = getPskType(result);
201         networkId = -1;
202         mRssi = result.level;
203         mScanResult = result;
204     }
205 
206     @Override
onBindView(View view)207     protected void onBindView(View view) {
208         super.onBindView(view);
209         ImageView signal = (ImageView) view.findViewById(R.id.signal);
210         if (mRssi == Integer.MAX_VALUE) {
211             signal.setImageDrawable(null);
212         } else {
213             signal.setImageLevel(getLevel());
214             signal.setImageResource(R.drawable.wifi_signal);
215             signal.setImageState((security != SECURITY_NONE) ?
216                     STATE_SECURED : STATE_NONE, true);
217         }
218     }
219 
220     @Override
compareTo(Preference preference)221     public int compareTo(Preference preference) {
222         if (!(preference instanceof AccessPoint)) {
223             return 1;
224         }
225         AccessPoint other = (AccessPoint) preference;
226         // Active one goes first.
227         if (mInfo != other.mInfo) {
228             return (mInfo != null) ? -1 : 1;
229         }
230         // Reachable one goes before unreachable one.
231         if ((mRssi ^ other.mRssi) < 0) {
232             return (mRssi != Integer.MAX_VALUE) ? -1 : 1;
233         }
234         // Configured one goes before unconfigured one.
235         if ((networkId ^ other.networkId) < 0) {
236             return (networkId != -1) ? -1 : 1;
237         }
238         // Sort by signal strength.
239         int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
240         if (difference != 0) {
241             return difference;
242         }
243         // Sort by ssid.
244         return ssid.compareToIgnoreCase(other.ssid);
245     }
246 
update(ScanResult result)247     boolean update(ScanResult result) {
248         if (ssid.equals(result.SSID) && security == getSecurity(result)) {
249             if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) {
250                 int oldLevel = getLevel();
251                 mRssi = result.level;
252                 if (getLevel() != oldLevel) {
253                     notifyChanged();
254                 }
255             }
256             // This flag only comes from scans, is not easily saved in config
257             if (security == SECURITY_PSK) {
258                 pskType = getPskType(result);
259             }
260             refresh();
261             return true;
262         }
263         return false;
264     }
265 
update(WifiInfo info, DetailedState state)266     void update(WifiInfo info, DetailedState state) {
267         boolean reorder = false;
268         if (info != null && networkId != WifiConfiguration.INVALID_NETWORK_ID
269                 && networkId == info.getNetworkId()) {
270             reorder = (mInfo == null);
271             mRssi = info.getRssi();
272             mInfo = info;
273             mState = state;
274             refresh();
275         } else if (mInfo != null) {
276             reorder = true;
277             mInfo = null;
278             mState = null;
279             refresh();
280         }
281         if (reorder) {
282             notifyHierarchyChanged();
283         }
284     }
285 
getLevel()286     int getLevel() {
287         if (mRssi == Integer.MAX_VALUE) {
288             return -1;
289         }
290         return WifiManager.calculateSignalLevel(mRssi, 4);
291     }
292 
getConfig()293     WifiConfiguration getConfig() {
294         return mConfig;
295     }
296 
getInfo()297     WifiInfo getInfo() {
298         return mInfo;
299     }
300 
getState()301     DetailedState getState() {
302         return mState;
303     }
304 
removeDoubleQuotes(String string)305     static String removeDoubleQuotes(String string) {
306         int length = string.length();
307         if ((length > 1) && (string.charAt(0) == '"')
308                 && (string.charAt(length - 1) == '"')) {
309             return string.substring(1, length - 1);
310         }
311         return string;
312     }
313 
convertToQuotedString(String string)314     static String convertToQuotedString(String string) {
315         return "\"" + string + "\"";
316     }
317 
318     /** Updates the title and summary; may indirectly call notifyChanged()  */
refresh()319     private void refresh() {
320         setTitle(ssid);
321 
322         Context context = getContext();
323         if (mState != null) { // This is the active connection
324             setSummary(Summary.get(context, mState));
325         } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
326             setSummary(context.getString(R.string.wifi_not_in_range));
327         } else if (mConfig != null && mConfig.status == WifiConfiguration.Status.DISABLED) {
328             switch (mConfig.disableReason) {
329                 case WifiConfiguration.DISABLED_AUTH_FAILURE:
330                     setSummary(context.getString(R.string.wifi_disabled_password_failure));
331                     break;
332                 case WifiConfiguration.DISABLED_DHCP_FAILURE:
333                 case WifiConfiguration.DISABLED_DNS_FAILURE:
334                     setSummary(context.getString(R.string.wifi_disabled_network_failure));
335                     break;
336                 case WifiConfiguration.DISABLED_UNKNOWN_REASON:
337                     setSummary(context.getString(R.string.wifi_disabled_generic));
338             }
339         } else { // In range, not disabled.
340             StringBuilder summary = new StringBuilder();
341             if (mConfig != null) { // Is saved network
342                 summary.append(context.getString(R.string.wifi_remembered));
343             }
344 
345             if (security != SECURITY_NONE) {
346                 String securityStrFormat;
347                 if (summary.length() == 0) {
348                     securityStrFormat = context.getString(R.string.wifi_secured_first_item);
349                 } else {
350                     securityStrFormat = context.getString(R.string.wifi_secured_second_item);
351                 }
352                 summary.append(String.format(securityStrFormat, getSecurityString(true)));
353             }
354 
355             if (mConfig == null && wpsAvailable) { // Only list WPS available for unsaved networks
356                 if (summary.length() == 0) {
357                     summary.append(context.getString(R.string.wifi_wps_available_first_item));
358                 } else {
359                     summary.append(context.getString(R.string.wifi_wps_available_second_item));
360                 }
361             }
362             setSummary(summary.toString());
363         }
364     }
365 
366     /**
367      * Generate and save a default wifiConfiguration with common values.
368      * Can only be called for unsecured networks.
369      * @hide
370      */
generateOpenNetworkConfig()371     protected void generateOpenNetworkConfig() {
372         if (security != SECURITY_NONE)
373             throw new IllegalStateException();
374         if (mConfig != null)
375             return;
376         mConfig = new WifiConfiguration();
377         mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
378         mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
379     }
380 }
381