WifiSettings.java revision 065cd4be6471084863c6560b8404dfdeaf4f2154
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 17package com.android.settings.wifi; 18 19import com.android.settings.ProgressCategory; 20import com.android.settings.R; 21 22import android.content.BroadcastReceiver; 23import android.content.Context; 24import android.content.DialogInterface; 25import android.content.Intent; 26import android.content.IntentFilter; 27import android.net.NetworkInfo; 28import android.net.wifi.ScanResult; 29import android.net.wifi.SupplicantState; 30import android.net.wifi.WifiConfiguration; 31import android.net.wifi.WifiConfiguration.KeyMgmt; 32import android.net.wifi.WifiConfiguration.Status; 33import android.net.wifi.WifiInfo; 34import android.net.wifi.WifiManager; 35import android.os.Bundle; 36import android.os.Handler; 37import android.os.Message; 38import android.preference.CheckBoxPreference; 39import android.preference.Preference; 40import android.preference.PreferenceActivity; 41import android.preference.PreferenceScreen; 42import android.provider.Settings.Secure; 43import android.security.Credentials; 44import android.security.KeyStore; 45import android.text.TextUtils; 46import android.view.ContextMenu; 47import android.view.ContextMenu.ContextMenuInfo; 48import android.view.Menu; 49import android.view.MenuItem; 50import android.view.View; 51import android.widget.AdapterView.AdapterContextMenuInfo; 52import android.widget.Toast; 53 54import java.util.ArrayList; 55import java.util.List; 56 57public class WifiSettings extends PreferenceActivity implements DialogInterface.OnClickListener { 58 private static final int MENU_ID_SCAN = Menu.FIRST; 59 private static final int MENU_ID_ADVANCED = Menu.FIRST + 1; 60 private static final int MENU_ID_CONNECT = Menu.FIRST + 2; 61 private static final int MENU_ID_FORGET = Menu.FIRST + 3; 62 private static final int MENU_ID_MODIFY = Menu.FIRST + 4; 63 64 private final IntentFilter mFilter; 65 private final BroadcastReceiver mReceiver; 66 private final Scanner mScanner; 67 68 private WifiManager mWifiManager; 69 private WifiEnabler mWifiEnabler; 70 private CheckBoxPreference mNotifyOpenNetworks; 71 private ProgressCategory mAccessPoints; 72 private Preference mAddNetwork; 73 74 private NetworkInfo.DetailedState mLastState; 75 private WifiInfo mLastInfo; 76 private int mLastPriority; 77 78 private boolean mResetNetworks = false; 79 private int mKeyStoreNetworkId = -1; 80 81 private AccessPoint mSelected; 82 private WifiDialog mDialog; 83 84 public WifiSettings() { 85 mFilter = new IntentFilter(); 86 mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 87 mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 88 mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); 89 mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); 90 mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 91 mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); 92 93 mReceiver = new BroadcastReceiver() { 94 @Override 95 public void onReceive(Context context, Intent intent) { 96 handleEvent(intent); 97 } 98 }; 99 100 mScanner = new Scanner(); 101 } 102 103 @Override 104 protected void onCreate(Bundle savedInstanceState) { 105 super.onCreate(savedInstanceState); 106 107 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); 108 109 if (getIntent().getBooleanExtra("only_access_points", false)) { 110 addPreferencesFromResource(R.xml.wifi_access_points); 111 } else { 112 addPreferencesFromResource(R.xml.wifi_settings); 113 mWifiEnabler = new WifiEnabler(this, mWifiManager, 114 (CheckBoxPreference) findPreference("enable_wifi")); 115 mNotifyOpenNetworks = 116 (CheckBoxPreference) findPreference("notify_open_networks"); 117 mNotifyOpenNetworks.setChecked(Secure.getInt(getContentResolver(), 118 Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1); 119 } 120 121 mAccessPoints = (ProgressCategory) findPreference("access_points"); 122 mAccessPoints.setOrderingAsAdded(false); 123 mAddNetwork = findPreference("add_network"); 124 125 registerForContextMenu(getListView()); 126 } 127 128 @Override 129 protected void onResume() { 130 super.onResume(); 131 registerReceiver(mReceiver, mFilter); 132 if (mWifiEnabler != null) { 133 mWifiEnabler.resume(); 134 } 135 if (mKeyStoreNetworkId != -1 && KeyStore.getInstance().test() == KeyStore.NO_ERROR) { 136 connect(mKeyStoreNetworkId); 137 } 138 mKeyStoreNetworkId = -1; 139 } 140 141 @Override 142 protected void onPause() { 143 super.onPause(); 144 unregisterReceiver(mReceiver); 145 if (mWifiEnabler != null) { 146 mWifiEnabler.pause(); 147 } 148 mScanner.pause(); 149 if (mDialog != null) { 150 mDialog.dismiss(); 151 mDialog = null; 152 } 153 if (mResetNetworks) { 154 enableNetworks(); 155 } 156 } 157 158 @Override 159 public boolean onCreateOptionsMenu(Menu menu) { 160 menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan) 161 .setIcon(R.drawable.ic_menu_scan_network); 162 menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced) 163 .setIcon(android.R.drawable.ic_menu_manage); 164 return super.onCreateOptionsMenu(menu); 165 } 166 167 @Override 168 public boolean onOptionsItemSelected(MenuItem item) { 169 switch (item.getItemId()) { 170 case MENU_ID_SCAN: 171 mScanner.resume(); 172 return true; 173 case MENU_ID_ADVANCED: 174 startActivity(new Intent(this, AdvancedSettings.class)); 175 return true; 176 } 177 return super.onOptionsItemSelected(item); 178 } 179 180 @Override 181 public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) { 182 if (info instanceof AdapterContextMenuInfo) { 183 Preference preference = (Preference) getListView().getItemAtPosition( 184 ((AdapterContextMenuInfo) info).position); 185 186 if (preference instanceof AccessPoint) { 187 mSelected = (AccessPoint) preference; 188 menu.setHeaderTitle(mSelected.ssid); 189 if (mSelected.getLevel() != -1 && mSelected.getState() == null) { 190 menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect); 191 } 192 if (mSelected.networkId != -1) { 193 menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget); 194 if (mSelected.security != AccessPoint.SECURITY_NONE) { 195 menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify); 196 } 197 } 198 } 199 } 200 } 201 202 @Override 203 public boolean onContextItemSelected(MenuItem item) { 204 if (mSelected == null) { 205 return super.onContextItemSelected(item); 206 } 207 switch (item.getItemId()) { 208 case MENU_ID_CONNECT: 209 if (mSelected.networkId != -1) { 210 if (!requireKeyStore(mSelected.getConfig())) { 211 connect(mSelected.networkId); 212 } 213 } else if (mSelected.security == AccessPoint.SECURITY_NONE) { 214 // Shortcut for open networks. 215 WifiConfiguration config = new WifiConfiguration(); 216 config.SSID = mSelected.ssid; 217 config.allowedKeyManagement.set(KeyMgmt.NONE); 218 int networkId = mWifiManager.addNetwork(config); 219 mWifiManager.enableNetwork(networkId, false); 220 connect(networkId); 221 } else { 222 showDialog(mSelected, false); 223 } 224 return true; 225 case MENU_ID_FORGET: 226 forget(mSelected.networkId); 227 return true; 228 case MENU_ID_MODIFY: 229 showDialog(mSelected, true); 230 return true; 231 } 232 return super.onContextItemSelected(item); 233 } 234 235 @Override 236 public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) { 237 if (preference instanceof AccessPoint) { 238 mSelected = (AccessPoint) preference; 239 showDialog(mSelected, false); 240 } else if (preference == mAddNetwork) { 241 mSelected = null; 242 showDialog(null, true); 243 } else if (preference == mNotifyOpenNetworks) { 244 Secure.putInt(getContentResolver(), 245 Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 246 mNotifyOpenNetworks.isChecked() ? 1 : 0); 247 } else { 248 return super.onPreferenceTreeClick(screen, preference); 249 } 250 return true; 251 } 252 253 public void onClick(DialogInterface dialogInterface, int button) { 254 if (button == WifiDialog.BUTTON_FORGET && mSelected != null) { 255 forget(mSelected.networkId); 256 } else if (button == WifiDialog.BUTTON_SUBMIT) { 257 WifiConfiguration config = mDialog.getConfig(); 258 259 if (config == null) { 260 if (mSelected != null && !requireKeyStore(mSelected.getConfig())) { 261 connect(mSelected.networkId); 262 } 263 } else if (config.networkId != -1) { 264 if (mSelected != null) { 265 mWifiManager.updateNetwork(config); 266 saveNetworks(); 267 } 268 } else { 269 int networkId = mWifiManager.addNetwork(config); 270 if (networkId != -1) { 271 mWifiManager.enableNetwork(networkId, false); 272 config.networkId = networkId; 273 if (mDialog.edit || requireKeyStore(config)) { 274 saveNetworks(); 275 } else { 276 connect(networkId); 277 } 278 } 279 } 280 } 281 } 282 283 private void showDialog(AccessPoint accessPoint, boolean edit) { 284 if (mDialog != null) { 285 mDialog.dismiss(); 286 } 287 mDialog = new WifiDialog(this, this, accessPoint, edit); 288 mDialog.show(); 289 } 290 291 private boolean requireKeyStore(WifiConfiguration config) { 292 if (WifiDialog.requireKeyStore(config) && 293 KeyStore.getInstance().test() != KeyStore.NO_ERROR) { 294 mKeyStoreNetworkId = config.networkId; 295 Credentials.getInstance().unlock(this); 296 return true; 297 } 298 return false; 299 } 300 301 private void forget(int networkId) { 302 mWifiManager.removeNetwork(networkId); 303 saveNetworks(); 304 } 305 306 private void connect(int networkId) { 307 if (networkId == -1) { 308 return; 309 } 310 311 // Reset the priority of each network if it goes too high. 312 if (mLastPriority > 1000000) { 313 for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) { 314 AccessPoint accessPoint = (AccessPoint) mAccessPoints.getPreference(i); 315 if (accessPoint.networkId != -1) { 316 WifiConfiguration config = new WifiConfiguration(); 317 config.networkId = accessPoint.networkId; 318 config.priority = 0; 319 mWifiManager.updateNetwork(config); 320 } 321 } 322 mLastPriority = 0; 323 } 324 325 // Set to the highest priority and save the configuration. 326 WifiConfiguration config = new WifiConfiguration(); 327 config.networkId = networkId; 328 config.priority = ++mLastPriority; 329 mWifiManager.updateNetwork(config); 330 saveNetworks(); 331 332 // Connect to network by disabling others. 333 mWifiManager.enableNetwork(networkId, true); 334 mWifiManager.reconnect(); 335 mResetNetworks = true; 336 } 337 338 private void enableNetworks() { 339 for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) { 340 WifiConfiguration config = ((AccessPoint) mAccessPoints.getPreference(i)).getConfig(); 341 if (config != null && config.status != Status.ENABLED) { 342 mWifiManager.enableNetwork(config.networkId, false); 343 } 344 } 345 mResetNetworks = false; 346 } 347 348 private void saveNetworks() { 349 // Always save the configuration with all networks enabled. 350 enableNetworks(); 351 mWifiManager.saveConfiguration(); 352 updateAccessPoints(); 353 } 354 355 private void updateAccessPoints() { 356 List<AccessPoint> accessPoints = new ArrayList<AccessPoint>(); 357 358 List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks(); 359 if (configs != null) { 360 mLastPriority = 0; 361 for (WifiConfiguration config : configs) { 362 if (config.priority > mLastPriority) { 363 mLastPriority = config.priority; 364 } 365 366 // Shift the status to make enableNetworks() more efficient. 367 if (config.status == Status.CURRENT) { 368 config.status = Status.ENABLED; 369 } else if (mResetNetworks && config.status == Status.DISABLED) { 370 config.status = Status.CURRENT; 371 } 372 373 AccessPoint accessPoint = new AccessPoint(this, config); 374 accessPoint.update(mLastInfo, mLastState); 375 accessPoints.add(accessPoint); 376 } 377 } 378 379 List<ScanResult> results = mWifiManager.getScanResults(); 380 if (results != null) { 381 for (ScanResult result : results) { 382 // Ignore hidden and ad-hoc networks. 383 if (result.SSID == null || result.SSID.length() == 0 || 384 result.capabilities.contains("[IBSS]")) { 385 continue; 386 } 387 388 boolean found = false; 389 for (AccessPoint accessPoint : accessPoints) { 390 if (accessPoint.update(result)) { 391 found = true; 392 } 393 } 394 if (!found) { 395 accessPoints.add(new AccessPoint(this, result)); 396 } 397 } 398 } 399 400 mAccessPoints.removeAll(); 401 for (AccessPoint accessPoint : accessPoints) { 402 mAccessPoints.addPreference(accessPoint); 403 } 404 } 405 406 private void handleEvent(Intent intent) { 407 String action = intent.getAction(); 408 if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { 409 updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 410 WifiManager.WIFI_STATE_UNKNOWN)); 411 } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) { 412 updateAccessPoints(); 413 } else if (WifiManager.NETWORK_IDS_CHANGED_ACTION.equals(action)) { 414 if (mSelected != null && mSelected.networkId != -1) { 415 mSelected = null; 416 } 417 updateAccessPoints(); 418 } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) { 419 updateConnectionState(WifiInfo.getDetailedStateOf((SupplicantState) 420 intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE))); 421 } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { 422 updateConnectionState(((NetworkInfo) intent.getParcelableExtra( 423 WifiManager.EXTRA_NETWORK_INFO)).getDetailedState()); 424 } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) { 425 updateConnectionState(null); 426 } 427 } 428 429 private void updateConnectionState(NetworkInfo.DetailedState state) { 430 if (state == NetworkInfo.DetailedState.OBTAINING_IPADDR) { 431 mScanner.pause(); 432 } else { 433 mScanner.resume(); 434 } 435 436 mLastInfo = mWifiManager.getConnectionInfo(); 437 if (state != null) { 438 mLastState = state; 439 } 440 441 for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) { 442 ((AccessPoint) mAccessPoints.getPreference(i)).update(mLastInfo, mLastState); 443 } 444 } 445 446 private void updateWifiState(int state) { 447 if (state == WifiManager.WIFI_STATE_ENABLED) { 448 mScanner.resume(); 449 updateAccessPoints(); 450 } else { 451 mScanner.pause(); 452 mAccessPoints.removeAll(); 453 } 454 } 455 456 private class Scanner extends Handler { 457 private int mRetry = 0; 458 459 void resume() { 460 if (!hasMessages(0)) { 461 sendEmptyMessage(0); 462 } 463 } 464 465 void pause() { 466 mRetry = 0; 467 mAccessPoints.setProgress(false); 468 removeMessages(0); 469 } 470 471 @Override 472 public void handleMessage(Message message) { 473 if (mWifiManager.startScanActive()) { 474 mRetry = 0; 475 } else if (++mRetry >= 3) { 476 mRetry = 0; 477 Toast.makeText(WifiSettings.this, R.string.wifi_fail_to_scan, 478 Toast.LENGTH_LONG).show(); 479 } 480 mAccessPoints.setProgress(mRetry != 0); 481 sendEmptyMessageDelayed(0, 6000); 482 } 483 } 484} 485