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