• 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 != null && other.mInfo == null) return -1;
228         if (mInfo == null && other.mInfo != null) return 1;
229 
230         // Reachable one goes before unreachable one.
231         if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1;
232         if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1;
233 
234         // Configured one goes before unconfigured one.
235         if (networkId != WifiConfiguration.INVALID_NETWORK_ID
236                 && other.networkId == WifiConfiguration.INVALID_NETWORK_ID) return -1;
237         if (networkId == WifiConfiguration.INVALID_NETWORK_ID
238                 && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1;
239 
240         // Sort by signal strength.
241         int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
242         if (difference != 0) {
243             return difference;
244         }
245         // Sort by ssid.
246         return ssid.compareToIgnoreCase(other.ssid);
247     }
248 
249     @Override
equals(Object other)250     public boolean equals(Object other) {
251         if (!(other instanceof AccessPoint)) return false;
252         return (this.compareTo((AccessPoint) other) == 0);
253     }
254 
255     @Override
hashCode()256     public int hashCode() {
257         int result = 0;
258         if (mInfo != null) result += 13 * mInfo.hashCode();
259         result += 19 * mRssi;
260         result += 23 * networkId;
261         result += 29 * ssid.hashCode();
262         return result;
263     }
264 
update(ScanResult result)265     boolean update(ScanResult result) {
266         if (ssid.equals(result.SSID) && security == getSecurity(result)) {
267             if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) {
268                 int oldLevel = getLevel();
269                 mRssi = result.level;
270                 if (getLevel() != oldLevel) {
271                     notifyChanged();
272                 }
273             }
274             // This flag only comes from scans, is not easily saved in config
275             if (security == SECURITY_PSK) {
276                 pskType = getPskType(result);
277             }
278             refresh();
279             return true;
280         }
281         return false;
282     }
283 
update(WifiInfo info, DetailedState state)284     void update(WifiInfo info, DetailedState state) {
285         boolean reorder = false;
286         if (info != null && networkId != WifiConfiguration.INVALID_NETWORK_ID
287                 && networkId == info.getNetworkId()) {
288             reorder = (mInfo == null);
289             mRssi = info.getRssi();
290             mInfo = info;
291             mState = state;
292             refresh();
293         } else if (mInfo != null) {
294             reorder = true;
295             mInfo = null;
296             mState = null;
297             refresh();
298         }
299         if (reorder) {
300             notifyHierarchyChanged();
301         }
302     }
303 
getLevel()304     int getLevel() {
305         if (mRssi == Integer.MAX_VALUE) {
306             return -1;
307         }
308         return WifiManager.calculateSignalLevel(mRssi, 4);
309     }
310 
getConfig()311     WifiConfiguration getConfig() {
312         return mConfig;
313     }
314 
getInfo()315     WifiInfo getInfo() {
316         return mInfo;
317     }
318 
getState()319     DetailedState getState() {
320         return mState;
321     }
322 
removeDoubleQuotes(String string)323     static String removeDoubleQuotes(String string) {
324         int length = string.length();
325         if ((length > 1) && (string.charAt(0) == '"')
326                 && (string.charAt(length - 1) == '"')) {
327             return string.substring(1, length - 1);
328         }
329         return string;
330     }
331 
convertToQuotedString(String string)332     static String convertToQuotedString(String string) {
333         return "\"" + string + "\"";
334     }
335 
336     /** Updates the title and summary; may indirectly call notifyChanged()  */
refresh()337     private void refresh() {
338         setTitle(ssid);
339 
340         Context context = getContext();
341         if (mState != null) { // This is the active connection
342             setSummary(Summary.get(context, mState));
343         } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
344             setSummary(context.getString(R.string.wifi_not_in_range));
345         } else if (mConfig != null && mConfig.status == WifiConfiguration.Status.DISABLED) {
346             switch (mConfig.disableReason) {
347                 case WifiConfiguration.DISABLED_AUTH_FAILURE:
348                     setSummary(context.getString(R.string.wifi_disabled_password_failure));
349                     break;
350                 case WifiConfiguration.DISABLED_DHCP_FAILURE:
351                 case WifiConfiguration.DISABLED_DNS_FAILURE:
352                     setSummary(context.getString(R.string.wifi_disabled_network_failure));
353                     break;
354                 case WifiConfiguration.DISABLED_UNKNOWN_REASON:
355                     setSummary(context.getString(R.string.wifi_disabled_generic));
356             }
357         } else { // In range, not disabled.
358             StringBuilder summary = new StringBuilder();
359             if (mConfig != null) { // Is saved network
360                 summary.append(context.getString(R.string.wifi_remembered));
361             }
362 
363             if (security != SECURITY_NONE) {
364                 String securityStrFormat;
365                 if (summary.length() == 0) {
366                     securityStrFormat = context.getString(R.string.wifi_secured_first_item);
367                 } else {
368                     securityStrFormat = context.getString(R.string.wifi_secured_second_item);
369                 }
370                 summary.append(String.format(securityStrFormat, getSecurityString(true)));
371             }
372 
373             if (mConfig == null && wpsAvailable) { // Only list WPS available for unsaved networks
374                 if (summary.length() == 0) {
375                     summary.append(context.getString(R.string.wifi_wps_available_first_item));
376                 } else {
377                     summary.append(context.getString(R.string.wifi_wps_available_second_item));
378                 }
379             }
380             setSummary(summary.toString());
381         }
382     }
383 
384     /**
385      * Generate and save a default wifiConfiguration with common values.
386      * Can only be called for unsecured networks.
387      * @hide
388      */
generateOpenNetworkConfig()389     protected void generateOpenNetworkConfig() {
390         if (security != SECURITY_NONE)
391             throw new IllegalStateException();
392         if (mConfig != null)
393             return;
394         mConfig = new WifiConfiguration();
395         mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
396         mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
397     }
398 }
399