WifiSettings.java revision eb7836f11ec4e9753db7c6ecd9414e153bb7bdbe
1/* 2 * Copyright (C) 2007 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; 21import com.android.settings.SecuritySettings; 22 23import android.app.Dialog; 24import android.content.DialogInterface; 25import android.content.Intent; 26import android.net.wifi.WifiManager; 27import android.os.Bundle; 28import android.preference.Preference; 29import android.preference.PreferenceActivity; 30import android.preference.PreferenceScreen; 31import android.preference.CheckBoxPreference; 32import android.provider.Settings; 33import android.security.Keystore; 34import android.util.Log; 35import android.view.ContextMenu; 36import android.view.Menu; 37import android.view.MenuItem; 38import android.view.View; 39import android.view.ContextMenu.ContextMenuInfo; 40import android.widget.AdapterView; 41import android.widget.Toast; 42import android.widget.AdapterView.AdapterContextMenuInfo; 43 44import java.util.Set; 45import java.util.WeakHashMap; 46 47/** 48 * Settings screen for WiFi. This will be launched from the main system settings. 49 */ 50public class WifiSettings extends PreferenceActivity implements WifiLayer.Callback, 51 DialogInterface.OnDismissListener { 52 53 private static final String TAG = "WifiSettings"; 54 55 //============================ 56 // Preference/activity member variables 57 //============================ 58 59 private static final String INSTANCE_KEY_DIALOG_BUNDLE = 60 "com.android.settings.wifi.WifiSettings:dialogBundle"; 61 /* 62 * We don't use Activity's dialog management because AlertDialog isn't fully 63 * able to change many of its features after it's been created, and the 64 * dialog management only creates once. 65 */ 66 private Dialog mDialog; 67 68 private static final String KEY_ADD_OTHER_NETWORK = "add_other_network"; 69 70 private static final int CONTEXT_MENU_ID_CONNECT = Menu.FIRST; 71 private static final int CONTEXT_MENU_ID_FORGET = Menu.FIRST + 1; 72 private static final int CONTEXT_MENU_ID_CHANGE_PASSWORD = Menu.FIRST + 2; 73 74 private static final int MENU_ID_SCAN = Menu.FIRST; 75 private static final int MENU_ID_ADVANCED = Menu.FIRST + 1; 76 77 private static final String KEY_WIFI_ENABLED = "wifi_enabled"; 78 private static final String KEY_OPEN_NETWORK_NOTIFICATIONS_ENABLED = 79 "open_network_notifications_enabled"; 80 private static final String KEY_ACCESS_POINTS = "access_points"; 81 82 private ProgressCategory mApCategory; 83 private CheckBoxPreference mWifiEnabled; 84 private WifiEnabler mWifiEnabler; 85 private CheckBoxPreference mOpenNetworkNotificationsEnabled; 86 private Preference mAddOtherNetwork; 87 88 private WeakHashMap<AccessPointState, AccessPointPreference> mAps; 89 90 //============================ 91 // Wifi member variables 92 //============================ 93 94 private WifiLayer mWifiLayer; 95 96 //============================ 97 // Activity lifecycle 98 //============================ 99 100 public WifiSettings() { 101 mAps = new WeakHashMap<AccessPointState, AccessPointPreference>(); 102 mWifiLayer = new WifiLayer(this, this); 103 } 104 105 @Override 106 protected void onCreate(Bundle savedInstanceState) { 107 super.onCreate(savedInstanceState); 108 109 onCreatePreferences(); 110 mWifiLayer.onCreate(); 111 112 onCreatedWifi(); 113 mWifiLayer.onCreatedCallback(); 114 } 115 116 /** 117 * Shouldn't have any dependency on the wifi layer. 118 */ 119 private void onCreatePreferences() { 120 addPreferencesFromResource(R.xml.wifi_settings); 121 122 final PreferenceScreen preferenceScreen = getPreferenceScreen(); 123 124 mApCategory = (ProgressCategory) preferenceScreen.findPreference(KEY_ACCESS_POINTS); 125 // We don't want the ordering to be the order preferences are added, 126 // instead we want*: 127 // 1) preferred, visible APs 128 // 2) visible APs 129 // 3) preferred, APs out of range 130 // * this ordering logic is in AccessPointPreference's compareTo 131 mApCategory.setOrderingAsAdded(false); 132 133 mWifiEnabled = (CheckBoxPreference) preferenceScreen.findPreference(KEY_WIFI_ENABLED); 134 mWifiEnabler = new WifiEnabler(this, (WifiManager) getSystemService(WIFI_SERVICE), 135 mWifiEnabled); 136 137 mOpenNetworkNotificationsEnabled = (CheckBoxPreference) preferenceScreen 138 .findPreference(KEY_OPEN_NETWORK_NOTIFICATIONS_ENABLED); 139 mOpenNetworkNotificationsEnabled.setChecked(Settings.Secure.getInt(getContentResolver(), 140 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1); 141 142 mAddOtherNetwork = preferenceScreen.findPreference(KEY_ADD_OTHER_NETWORK); 143 144 registerForContextMenu(getListView()); 145 } 146 147 private void onCreatedWifi() { 148 } 149 150 @Override 151 protected void onResume() { 152 super.onResume(); 153 mWifiLayer.onResume(); 154 mWifiEnabler.resume(); 155 } 156 157 @Override 158 protected void onPause() { 159 super.onPause(); 160 mWifiLayer.onPause(); 161 mWifiEnabler.pause(); 162 } 163 164 @Override 165 protected void onDestroy() { 166 super.onDestroy(); 167 168 if (mDialog != null) { 169 mDialog.dismiss(); 170 } 171 } 172 173 @Override 174 public boolean onCreateOptionsMenu(Menu menu) { 175 super.onCreateOptionsMenu(menu); 176 177 menu.add(0, MENU_ID_SCAN, 0, R.string.scan_wifi) 178 .setIcon(R.drawable.ic_menu_scan_network); 179 180 menu.add(0, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced) 181 .setIcon(android.R.drawable.ic_menu_manage); 182 183 return true; 184 } 185 186 @Override 187 public boolean onOptionsItemSelected(MenuItem item) { 188 super.onOptionsItemSelected(item); 189 190 switch (item.getItemId()) { 191 192 case MENU_ID_SCAN: 193 mWifiLayer.attemptScan(); 194 return true; 195 196 case MENU_ID_ADVANCED: 197 Intent intent = new Intent(this, AdvancedSettings.class); 198 startActivity(intent); 199 return true; 200 201 default: 202 return false; 203 } 204 } 205 206 @Override 207 protected void onSaveInstanceState(Bundle outState) { 208 super.onSaveInstanceState(outState); 209 210 if (mDialog != null) { 211 Bundle dialogBundle = mDialog.onSaveInstanceState(); 212 outState.putBundle(INSTANCE_KEY_DIALOG_BUNDLE, dialogBundle); 213 } 214 } 215 216 @Override 217 protected void onRestoreInstanceState(Bundle state) { 218 super.onRestoreInstanceState(state); 219 220 Bundle dialogBundle = state.getBundle(INSTANCE_KEY_DIALOG_BUNDLE); 221 if (dialogBundle != null) { 222 mDialog = new AccessPointDialog(this, mWifiLayer); 223 mDialog.onRestoreInstanceState(dialogBundle); 224 showDialog(mDialog); 225 } 226 } 227 228 /** 229 * {@inheritDoc} 230 */ 231 public void onDismiss(DialogInterface dialog) { 232 if (dialog == mDialog) { 233 mDialog = null; 234 } 235 } 236 237 @Override 238 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 239 super.onCreateContextMenu(menu, v, menuInfo); 240 241 AccessPointState state = getStateFromMenuInfo(menuInfo); 242 if (state == null) { 243 return; 244 } 245 246 menu.setHeaderTitle(state.getHumanReadableSsid()); 247 248 if (state.isConnectable()) { 249 menu.add(0, CONTEXT_MENU_ID_CONNECT, 0, R.string.wifi_context_menu_connect); 250 } 251 252 if (state.isForgetable()) { 253 menu.add(0, CONTEXT_MENU_ID_FORGET, 1, R.string.wifi_context_menu_forget); 254 255 if (state.hasPassword()) { 256 menu.add(0, CONTEXT_MENU_ID_CHANGE_PASSWORD, 2, 257 R.string.wifi_context_menu_change_password); 258 } 259 } 260 } 261 262 @Override 263 public boolean onContextItemSelected(MenuItem item) { 264 265 AccessPointState state = getStateFromMenuInfo(item.getMenuInfo()); 266 if (state == null) { 267 return false; 268 } 269 270 switch (item.getItemId()) { 271 272 case CONTEXT_MENU_ID_CONNECT: 273 connectToNetwork(state); 274 return true; 275 276 case CONTEXT_MENU_ID_FORGET: 277 mWifiLayer.forgetNetwork(state); 278 return true; 279 280 case CONTEXT_MENU_ID_CHANGE_PASSWORD: 281 showAccessPointDialog(state, AccessPointDialog.MODE_CONFIGURE); 282 return true; 283 284 default: 285 return false; 286 } 287 } 288 289 /** 290 * Decides what needs to happen to connect to a particular access point. If 291 * it is secured and doesn't already have a password, it will bring up a 292 * password box. Otherwise it will just connect. 293 */ 294 private void connectToNetwork(AccessPointState state) { 295 if (state.hasSecurity() && !state.hasPassword()) { 296 showAccessPointDialog(state, AccessPointDialog.MODE_INFO); 297 } else { 298 mWifiLayer.connectToNetwork(state); 299 } 300 } 301 302 private AccessPointState getStateFromMenuInfo(ContextMenuInfo menuInfo) { 303 if ((menuInfo == null) || !(menuInfo instanceof AdapterContextMenuInfo)) { 304 return null; 305 } 306 307 AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo; 308 Preference pref = (Preference) getPreferenceScreen().getRootAdapter().getItem( 309 adapterMenuInfo.position); 310 if (pref == null || !(pref instanceof AccessPointPreference)) { 311 return null; 312 } 313 314 return ((AccessPointPreference) pref).getAccessPointState(); 315 } 316 317 //============================ 318 // Preference callbacks 319 //============================ 320 321 @Override 322 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 323 super.onPreferenceTreeClick(preferenceScreen, preference); 324 325 if (preference == mAddOtherNetwork) { 326 showAddOtherNetworkDialog(); 327 } else if (preference == mOpenNetworkNotificationsEnabled) { 328 Settings.Secure.putInt(getContentResolver(), 329 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 330 mOpenNetworkNotificationsEnabled.isChecked() ? 1 : 0); 331 } else if (preference instanceof AccessPointPreference) { 332 AccessPointState state = ((AccessPointPreference) preference).getAccessPointState(); 333 showAccessPointDialog(state, AccessPointDialog.MODE_INFO); 334 } 335 336 return false; 337 } 338 339 //============================ 340 // Wifi-related 341 //============================ 342 343 public WifiLayer getWifiLayer() { 344 return mWifiLayer; 345 } 346 347 private void showAddOtherNetworkDialog() { 348 AccessPointDialog dialog = new AccessPointDialog(this, mWifiLayer); 349 dialog.setState(new AccessPointState(this)); 350 dialog.setMode(AccessPointDialog.MODE_CONFIGURE); 351 dialog.setTitle(R.string.wifi_add_other_network); 352 dialog.setAutoSecurityAllowed(false); 353 showDialog(dialog); 354 } 355 356 public void showAccessPointDialog(AccessPointState state, int mode) { 357 if (state.isEnterprise() && 358 Keystore.getInstance().getState() != Keystore.UNLOCKED) { 359 startActivity(new Intent( 360 SecuritySettings.ACTION_UNLOCK_CREDENTIAL_STORAGE)); 361 return; 362 } 363 AccessPointDialog dialog = new AccessPointDialog(this, mWifiLayer); 364 dialog.setMode(mode); 365 dialog.setState(state); 366 showDialog(dialog); 367 } 368 369 private void showDialog(Dialog dialog) { 370 // Have only one dialog open at a time 371 if (mDialog != null) { 372 mDialog.dismiss(); 373 } 374 375 mDialog = dialog; 376 dialog.setOnDismissListener(this); 377 if (dialog != null) { 378 dialog.show(); 379 } 380 } 381 382 //============================ 383 // Wifi callbacks 384 //============================ 385 386 public void onError(int messageResId) { 387 Toast.makeText(this, messageResId, Toast.LENGTH_LONG).show(); 388 } 389 390 public void onScanningStatusChanged(boolean started) { 391 mApCategory.setProgress(started); 392 } 393 394 public void onAccessPointSetChanged(AccessPointState ap, boolean added) { 395 396 AccessPointPreference pref = mAps.get(ap); 397 398 if (WifiLayer.LOGV) { 399 Log.v(TAG, "onAccessPointSetChanged with " + ap + " and " 400 + (added ? "added" : "removed") + ", found pref " + pref); 401 } 402 403 if (added) { 404 405 if (pref == null) { 406 pref = new AccessPointPreference(this, ap); 407 mAps.put(ap, pref); 408 } else { 409 pref.setEnabled(true); 410 } 411 412 mApCategory.addPreference(pref); 413 414 } else { 415 416 mAps.remove(ap); 417 418 if (pref != null) { 419 mApCategory.removePreference(pref); 420 } 421 422 } 423 } 424 425 public void onAccessPointsStateChanged(boolean enabled) { 426 if (enabled) { 427 mApCategory.setEnabled(true); 428 } else { 429 mApCategory.removeAll(); 430 mAps.clear(); 431 } 432 433 mAddOtherNetwork.setEnabled(enabled); 434 } 435 436 public void onRetryPassword(AccessPointState ap) { 437 438 if ((mDialog != null) && mDialog.isShowing()) { 439 // If we're already showing a dialog, ignore this request 440 return; 441 } 442 443 showAccessPointDialog(ap, AccessPointDialog.MODE_RETRY_PASSWORD); 444 } 445 446} 447