WifiSettings.java revision c1eab91f073313d84e67b4626f008aa3520c9f3a
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 static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; 20 21import android.app.ActionBar; 22import android.app.Activity; 23import android.app.AlertDialog; 24import android.app.Dialog; 25import android.content.BroadcastReceiver; 26import android.content.Context; 27import android.content.DialogInterface; 28import android.content.Intent; 29import android.content.IntentFilter; 30import android.net.ConnectivityManager; 31import android.net.NetworkInfo; 32import android.net.NetworkInfo.DetailedState; 33import android.net.wifi.ScanResult; 34import android.net.wifi.SupplicantState; 35import android.net.wifi.WifiConfiguration; 36import android.net.wifi.WifiConfiguration.KeyMgmt; 37import android.net.wifi.WifiInfo; 38import android.net.wifi.WifiManager; 39import android.net.wifi.WpsResult; 40import android.os.Bundle; 41import android.os.Handler; 42import android.os.Message; 43import android.preference.Preference; 44import android.preference.PreferenceActivity; 45import android.preference.PreferenceScreen; 46import android.security.Credentials; 47import android.security.KeyStore; 48import android.util.Log; 49import android.view.ContextMenu; 50import android.view.ContextMenu.ContextMenuInfo; 51import android.view.Gravity; 52import android.view.LayoutInflater; 53import android.view.Menu; 54import android.view.MenuInflater; 55import android.view.MenuItem; 56import android.view.View; 57import android.view.ViewGroup; 58import android.widget.AdapterView.AdapterContextMenuInfo; 59import android.widget.Switch; 60import android.widget.TextView; 61import android.widget.Toast; 62 63import com.android.internal.util.AsyncChannel; 64import com.android.settings.R; 65import com.android.settings.SettingsPreferenceFragment; 66 67import java.util.ArrayList; 68import java.util.Collection; 69import java.util.List; 70import java.util.concurrent.atomic.AtomicBoolean; 71 72/** 73 * This currently provides three types of UI. 74 * 75 * Two are for phones with relatively small screens: "for SetupWizard" and "for usual Settings". 76 * Users just need to launch WifiSettings Activity as usual. The request will be appropriately 77 * handled by ActivityManager, and they will have appropriate look-and-feel with this fragment. 78 * 79 * Third type is for Setup Wizard with X-Large, landscape UI. Users need to launch 80 * {@link WifiSettingsForSetupWizardXL} Activity, which contains this fragment but also has 81 * other decorations specific to that screen. 82 */ 83public class WifiSettings extends SettingsPreferenceFragment 84 implements DialogInterface.OnClickListener { 85 private static final String TAG = "WifiSettings"; 86 private static final int MENU_ID_SCAN = Menu.FIRST; 87 private static final int MENU_ID_ADD_NETWORK = Menu.FIRST + 1; 88 private static final int MENU_ID_ADVANCED = Menu.FIRST + 2; 89 private static final int MENU_ID_CONNECT = Menu.FIRST + 3; 90 private static final int MENU_ID_FORGET = Menu.FIRST + 4; 91 private static final int MENU_ID_MODIFY = Menu.FIRST + 5; 92 93 private static final int WIFI_DIALOG_ID = 1; 94 95 // Instance state keys 96 private static final String SAVE_DIALOG_EDIT_MODE = "edit_mode"; 97 private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state"; 98 99 private final IntentFilter mFilter; 100 private final BroadcastReceiver mReceiver; 101 private final Scanner mScanner; 102 103 private WifiManager mWifiManager; 104 private WifiEnabler mWifiEnabler; 105 // An access point being editted is stored here. 106 private AccessPoint mSelectedAccessPoint; 107 108 private DetailedState mLastState; 109 private WifiInfo mLastInfo; 110 111 private AtomicBoolean mConnected = new AtomicBoolean(false); 112 113 private int mKeyStoreNetworkId = INVALID_NETWORK_ID; 114 115 private WifiDialog mDialog; 116 117 private View mView; 118 private TextView mEmptyView; 119 120 /* Used in Wifi Setup context */ 121 122 // this boolean extra specifies whether to disable the Next button when not connected 123 private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect"; 124 125 // should Next button only be enabled when we have a connection? 126 private boolean mEnableNextOnConnection; 127 private boolean mInXlSetupWizard; 128 129 // Save the dialog details 130 private boolean mDlgEdit; 131 private AccessPoint mDlgAccessPoint; 132 private Bundle mAccessPointSavedState; 133 134 /* End of "used in Wifi Setup context" */ 135 136 public WifiSettings() { 137 mFilter = new IntentFilter(); 138 mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 139 mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 140 mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); 141 mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); 142 mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 143 mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 144 mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 145 mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); 146 mFilter.addAction(WifiManager.ERROR_ACTION); 147 148 mReceiver = new BroadcastReceiver() { 149 @Override 150 public void onReceive(Context context, Intent intent) { 151 handleEvent(context, intent); 152 } 153 }; 154 155 mScanner = new Scanner(); 156 } 157 158 @Override 159 public void onAttach(Activity activity) { 160 super.onAttach(activity); 161 162 mInXlSetupWizard = (activity instanceof WifiSettingsForSetupWizardXL); 163 } 164 165 @Override 166 public View onCreateView(LayoutInflater inflater, ViewGroup container, 167 Bundle savedInstanceState) { 168 mView = inflater.inflate(R.layout.custom_preference_list_fragment, container, false); 169 return mView; 170 } 171 172 @Override 173 public void onActivityCreated(Bundle savedInstanceState) { 174 // We don't call super.onActivityCreated() here, since it assumes we already set up 175 // Preference (probably in onCreate()), while WifiSettings exceptionally set it up in 176 // this method. 177 178 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); 179 mWifiManager.asyncConnect(getActivity(), new WifiServiceHandler()); 180 if (savedInstanceState != null 181 && savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) { 182 mDlgEdit = savedInstanceState.getBoolean(SAVE_DIALOG_EDIT_MODE); 183 mAccessPointSavedState = savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE); 184 } 185 186 final Activity activity = getActivity(); 187 final Intent intent = activity.getIntent(); 188 189 // if we're supposed to enable/disable the Next button based on our current connection 190 // state, start it off in the right state 191 mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false); 192 193 if (mEnableNextOnConnection) { 194 if (hasNextButton()) { 195 final ConnectivityManager connectivity = (ConnectivityManager) 196 getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); 197 if (connectivity != null) { 198 NetworkInfo info = connectivity.getNetworkInfo( 199 ConnectivityManager.TYPE_WIFI); 200 changeNextButtonState(info.isConnected()); 201 } 202 } 203 } 204 205 if (mInXlSetupWizard) { 206 addPreferencesFromResource(R.xml.wifi_access_points_for_wifi_setup_xl); 207 } else { 208 addPreferencesFromResource(R.xml.wifi_settings); 209 210 Switch actionBarSwitch = new Switch(activity); 211 212 if (activity instanceof PreferenceActivity) { 213 PreferenceActivity preferenceActivity = (PreferenceActivity) activity; 214 if (preferenceActivity.onIsHidingHeaders() || !preferenceActivity.onIsMultiPane()) { 215 final int padding = activity.getResources().getDimensionPixelSize( 216 R.dimen.action_bar_switch_padding); 217 actionBarSwitch.setPadding(0, 0, padding, 0); 218 activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, 219 ActionBar.DISPLAY_SHOW_CUSTOM); 220 activity.getActionBar().setCustomView(actionBarSwitch, new ActionBar.LayoutParams( 221 ActionBar.LayoutParams.WRAP_CONTENT, 222 ActionBar.LayoutParams.WRAP_CONTENT, 223 Gravity.CENTER_VERTICAL | Gravity.RIGHT)); 224 } 225 } 226 227 mWifiEnabler = new WifiEnabler(activity, actionBarSwitch); 228 } 229 230 mEmptyView = (TextView) mView.findViewById(R.id.empty); 231 getListView().setEmptyView(mEmptyView); 232 233 registerForContextMenu(getListView()); 234 setHasOptionsMenu(true); 235 236 // After confirming PreferenceScreen is available, we call super. 237 super.onActivityCreated(savedInstanceState); 238 } 239 240 @Override 241 public void onResume() { 242 super.onResume(); 243 if (mWifiEnabler != null) { 244 mWifiEnabler.resume(); 245 } 246 247 getActivity().registerReceiver(mReceiver, mFilter); 248 if (mKeyStoreNetworkId != INVALID_NETWORK_ID && 249 KeyStore.getInstance().state() == KeyStore.State.UNLOCKED) { 250 mWifiManager.connectNetwork(mKeyStoreNetworkId); 251 } 252 mKeyStoreNetworkId = INVALID_NETWORK_ID; 253 254 updateAccessPoints(); 255 } 256 257 @Override 258 public void onPause() { 259 super.onPause(); 260 if (mWifiEnabler != null) { 261 mWifiEnabler.pause(); 262 } 263 getActivity().unregisterReceiver(mReceiver); 264 mScanner.pause(); 265 } 266 267 @Override 268 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 269 // We don't want menus in Setup Wizard XL. 270 if (!mInXlSetupWizard) { 271 final boolean wifiIsEnabled = mWifiManager.isWifiEnabled(); 272 menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan) 273 //.setIcon(R.drawable.ic_menu_scan_network) 274 .setEnabled(wifiIsEnabled) 275 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 276 menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network) 277 .setEnabled(wifiIsEnabled) 278 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 279 menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced) 280 //.setIcon(android.R.drawable.ic_menu_manage) 281 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 282 } 283 super.onCreateOptionsMenu(menu, inflater); 284 } 285 286 @Override 287 public void onSaveInstanceState(Bundle outState) { 288 super.onSaveInstanceState(outState); 289 290 // If the dialog is showing, save its state. 291 if (mDialog != null && mDialog.isShowing()) { 292 outState.putBoolean(SAVE_DIALOG_EDIT_MODE, mDlgEdit); 293 if (mDlgAccessPoint != null) { 294 mAccessPointSavedState = new Bundle(); 295 mDlgAccessPoint.saveWifiState(mAccessPointSavedState); 296 outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState); 297 } 298 } 299 } 300 301 @Override 302 public boolean onOptionsItemSelected(MenuItem item) { 303 switch (item.getItemId()) { 304 case MENU_ID_SCAN: 305 if (mWifiManager.isWifiEnabled()) { 306 mScanner.forceScan(); 307 } 308 return true; 309 case MENU_ID_ADD_NETWORK: 310 if (mWifiManager.isWifiEnabled()) { 311 onAddNetworkPressed(); 312 } 313 return true; 314 case MENU_ID_ADVANCED: 315 if (getActivity() instanceof PreferenceActivity) { 316 ((PreferenceActivity) getActivity()).startPreferencePanel( 317 AdvancedWifiSettings.class.getCanonicalName(), 318 null, 319 R.string.wifi_advanced_titlebar, null, 320 this, 0); 321 } else { 322 startFragment(this, AdvancedWifiSettings.class.getCanonicalName(), -1, null); 323 } 324 return true; 325 } 326 return super.onOptionsItemSelected(item); 327 } 328 329 @Override 330 public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) { 331 if (mInXlSetupWizard) { 332 ((WifiSettingsForSetupWizardXL)getActivity()).onCreateContextMenu(menu, view, info); 333 } else if (info instanceof AdapterContextMenuInfo) { 334 Preference preference = (Preference) getListView().getItemAtPosition( 335 ((AdapterContextMenuInfo) info).position); 336 337 if (preference instanceof AccessPoint) { 338 mSelectedAccessPoint = (AccessPoint) preference; 339 menu.setHeaderTitle(mSelectedAccessPoint.ssid); 340 if (mSelectedAccessPoint.getLevel() != -1 341 && mSelectedAccessPoint.getState() == null) { 342 menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect); 343 } 344 if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) { 345 menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget); 346 menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify); 347 } 348 } 349 } 350 } 351 352 @Override 353 public boolean onContextItemSelected(MenuItem item) { 354 if (mSelectedAccessPoint == null) { 355 return super.onContextItemSelected(item); 356 } 357 switch (item.getItemId()) { 358 case MENU_ID_CONNECT: { 359 if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) { 360 if (!requireKeyStore(mSelectedAccessPoint.getConfig())) { 361 mWifiManager.connectNetwork(mSelectedAccessPoint.networkId); 362 } 363 } else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) { 364 // Shortcut for open networks. 365 WifiConfiguration config = new WifiConfiguration(); 366 config.SSID = AccessPoint.convertToQuotedString(mSelectedAccessPoint.ssid); 367 config.allowedKeyManagement.set(KeyMgmt.NONE); 368 mWifiManager.connectNetwork(config); 369 } else { 370 showConfigUi(mSelectedAccessPoint, true); 371 } 372 return true; 373 } 374 case MENU_ID_FORGET: { 375 mWifiManager.forgetNetwork(mSelectedAccessPoint.networkId); 376 return true; 377 } 378 case MENU_ID_MODIFY: { 379 showConfigUi(mSelectedAccessPoint, true); 380 return true; 381 } 382 } 383 return super.onContextItemSelected(item); 384 } 385 386 @Override 387 public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) { 388 if (preference instanceof AccessPoint) { 389 mSelectedAccessPoint = (AccessPoint) preference; 390 showConfigUi(mSelectedAccessPoint, false); 391 } else { 392 return super.onPreferenceTreeClick(screen, preference); 393 } 394 return true; 395 } 396 397 /** 398 * Shows an appropriate Wifi configuration component. 399 * Called when a user clicks "Add network" preference or one of available networks is selected. 400 */ 401 private void showConfigUi(AccessPoint accessPoint, boolean edit) { 402 if (mInXlSetupWizard) { 403 ((WifiSettingsForSetupWizardXL)getActivity()).showConfigUi(accessPoint, edit); 404 } else { 405 showDialog(accessPoint, edit); 406 } 407 } 408 409 private void showDialog(AccessPoint accessPoint, boolean edit) { 410 if (mDialog != null) { 411 removeDialog(WIFI_DIALOG_ID); 412 mDialog = null; 413 } 414 415 // Save the access point and edit mode 416 mDlgAccessPoint = accessPoint; 417 mDlgEdit = edit; 418 419 showDialog(WIFI_DIALOG_ID); 420 } 421 422 @Override 423 public Dialog onCreateDialog(int dialogId) { 424 AccessPoint ap = mDlgAccessPoint; // For manual launch 425 if (ap == null) { // For re-launch from saved state 426 if (mAccessPointSavedState != null) { 427 ap = new AccessPoint(getActivity(), mAccessPointSavedState); 428 // For repeated orientation changes 429 mDlgAccessPoint = ap; 430 } 431 } 432 // If it's still null, fine, it's for Add Network 433 mSelectedAccessPoint = ap; 434 mDialog = new WifiDialog(getActivity(), this, ap, mDlgEdit); 435 return mDialog; 436 } 437 438 private boolean requireKeyStore(WifiConfiguration config) { 439 if (WifiConfigController.requireKeyStore(config) && 440 KeyStore.getInstance().state() != KeyStore.State.UNLOCKED) { 441 mKeyStoreNetworkId = config.networkId; 442 Credentials.getInstance().unlock(getActivity()); 443 return true; 444 } 445 return false; 446 } 447 448 /** 449 * Shows the latest access points available with supplimental information like 450 * the strength of network and the security for it. 451 */ 452 private void updateAccessPoints() { 453 final int wifiState = mWifiManager.getWifiState(); 454 455 switch (wifiState) { 456 case WifiManager.WIFI_STATE_ENABLED: 457 getPreferenceScreen().removeAll(); 458 // AccessPoints are automatically sorted with TreeSet. 459 final Collection<AccessPoint> accessPoints = constructAccessPoints(); 460 if (mInXlSetupWizard) { 461 ((WifiSettingsForSetupWizardXL)getActivity()).onAccessPointsUpdated( 462 getPreferenceScreen(), accessPoints); 463 } else { 464 for (AccessPoint accessPoint : accessPoints) { 465 getPreferenceScreen().addPreference(accessPoint); 466 } 467 } 468 break; 469 470 case WifiManager.WIFI_STATE_ENABLING: 471 getPreferenceScreen().removeAll(); 472 break; 473 474 case WifiManager.WIFI_STATE_DISABLING: 475 addMessagePreference(R.string.wifi_stopping); 476 break; 477 478 case WifiManager.WIFI_STATE_DISABLED: 479 addMessagePreference(R.string.wifi_empty_list_wifi_off); 480 break; 481 } 482 } 483 484 private void addMessagePreference(int messageId) { 485 if (mEmptyView != null) mEmptyView.setText(messageId); 486 getPreferenceScreen().removeAll(); 487 } 488 489 private Collection<AccessPoint> constructAccessPoints() { 490 Collection<AccessPoint> accessPoints = new ArrayList<AccessPoint>(); 491 492 final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks(); 493 if (configs != null) { 494 for (WifiConfiguration config : configs) { 495 AccessPoint accessPoint = new AccessPoint(getActivity(), config); 496 accessPoint.update(mLastInfo, mLastState); 497 accessPoints.add(accessPoint); 498 } 499 } 500 501 final List<ScanResult> results = mWifiManager.getScanResults(); 502 if (results != null) { 503 for (ScanResult result : results) { 504 // Ignore hidden and ad-hoc networks. 505 if (result.SSID == null || result.SSID.length() == 0 || 506 result.capabilities.contains("[IBSS]")) { 507 continue; 508 } 509 510 boolean found = false; 511 for (AccessPoint accessPoint : accessPoints) { 512 if (accessPoint.update(result)) { 513 found = true; 514 } 515 } 516 if (!found) { 517 accessPoints.add(new AccessPoint(getActivity(), result)); 518 } 519 } 520 } 521 522 return accessPoints; 523 } 524 525 private void handleEvent(Context context, Intent intent) { 526 String action = intent.getAction(); 527 if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { 528 updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 529 WifiManager.WIFI_STATE_UNKNOWN)); 530 } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) || 531 WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) || 532 WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) { 533 updateAccessPoints(); 534 } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) { 535 //Ignore supplicant state changes when network is connected 536 //TODO: we should deprecate SUPPLICANT_STATE_CHANGED_ACTION and 537 //introduce a broadcast that combines the supplicant and network 538 //network state change events so the apps dont have to worry about 539 //ignoring supplicant state change when network is connected 540 //to get more fine grained information. 541 if (!mConnected.get()) { 542 updateConnectionState(WifiInfo.getDetailedStateOf((SupplicantState) 543 intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE))); 544 } 545 546 if (mInXlSetupWizard) { 547 ((WifiSettingsForSetupWizardXL)getActivity()).onSupplicantStateChanged(intent); 548 } 549 } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { 550 NetworkInfo info = (NetworkInfo) intent.getParcelableExtra( 551 WifiManager.EXTRA_NETWORK_INFO); 552 mConnected.set(info.isConnected()); 553 changeNextButtonState(info.isConnected()); 554 updateAccessPoints(); 555 updateConnectionState(info.getDetailedState()); 556 } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) { 557 updateConnectionState(null); 558 } else if (WifiManager.ERROR_ACTION.equals(action)) { 559 int errorCode = intent.getIntExtra(WifiManager.EXTRA_ERROR_CODE, 0); 560 switch (errorCode) { 561 case WifiManager.WPS_OVERLAP_ERROR: 562 Toast.makeText(context, R.string.wifi_wps_overlap_error, 563 Toast.LENGTH_SHORT).show(); 564 break; 565 } 566 } 567 } 568 569 private void updateConnectionState(DetailedState state) { 570 /* sticky broadcasts can call this when wifi is disabled */ 571 if (!mWifiManager.isWifiEnabled()) { 572 mScanner.pause(); 573 return; 574 } 575 576 if (state == DetailedState.OBTAINING_IPADDR) { 577 mScanner.pause(); 578 } else { 579 mScanner.resume(); 580 } 581 582 mLastInfo = mWifiManager.getConnectionInfo(); 583 if (state != null) { 584 mLastState = state; 585 } 586 587 for (int i = getPreferenceScreen().getPreferenceCount() - 1; i >= 0; --i) { 588 // Maybe there's a WifiConfigPreference 589 Preference preference = getPreferenceScreen().getPreference(i); 590 if (preference instanceof AccessPoint) { 591 final AccessPoint accessPoint = (AccessPoint) preference; 592 accessPoint.update(mLastInfo, mLastState); 593 } 594 } 595 596 if (mInXlSetupWizard) { 597 ((WifiSettingsForSetupWizardXL)getActivity()).updateConnectionState(mLastState); 598 } 599 } 600 601 private void updateWifiState(int state) { 602 getActivity().invalidateOptionsMenu(); 603 604 switch (state) { 605 case WifiManager.WIFI_STATE_ENABLED: 606 mScanner.resume(); 607 return; // not break, to avoid the call to pause() below 608 609 case WifiManager.WIFI_STATE_ENABLING: 610 addMessagePreference(R.string.wifi_starting); 611 break; 612 613 case WifiManager.WIFI_STATE_DISABLED: 614 addMessagePreference(R.string.wifi_empty_list_wifi_off); 615 break; 616 } 617 618 mLastInfo = null; 619 mLastState = null; 620 mScanner.pause(); 621 } 622 623 private class Scanner extends Handler { 624 private int mRetry = 0; 625 626 void resume() { 627 if (!hasMessages(0)) { 628 sendEmptyMessage(0); 629 } 630 } 631 632 void forceScan() { 633 sendEmptyMessage(0); 634 } 635 636 void pause() { 637 mRetry = 0; 638 removeMessages(0); 639 } 640 641 @Override 642 public void handleMessage(Message message) { 643 if (mWifiManager.startScanActive()) { 644 mRetry = 0; 645 } else if (++mRetry >= 3) { 646 mRetry = 0; 647 Toast.makeText(getActivity(), R.string.wifi_fail_to_scan, 648 Toast.LENGTH_LONG).show(); 649 return; 650 } 651 // Combo scans can take 5-6s to complete. Increase interval to 10s. 652 sendEmptyMessageDelayed(0, 10000); 653 } 654 } 655 656 private class WifiServiceHandler extends Handler { 657 658 @Override 659 public void handleMessage(Message msg) { 660 switch (msg.what) { 661 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 662 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 663 //AsyncChannel in msg.obj 664 } else { 665 //AsyncChannel set up failure, ignore 666 Log.e(TAG, "Failed to establish AsyncChannel connection"); 667 } 668 break; 669 case WifiManager.CMD_WPS_COMPLETED: 670 WpsResult result = (WpsResult) msg.obj; 671 if (result == null) break; 672 AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity()) 673 .setTitle(R.string.wifi_wps_setup_title) 674 .setPositiveButton(android.R.string.ok, null); 675 switch (result.status) { 676 case FAILURE: 677 dialog.setMessage(R.string.wifi_wps_failed); 678 dialog.show(); 679 break; 680 case IN_PROGRESS: 681 dialog.setMessage(R.string.wifi_wps_in_progress); 682 dialog.show(); 683 break; 684 default: 685 if (result.pin != null) { 686 dialog.setMessage(getResources().getString( 687 R.string.wifi_wps_pin_output, result.pin)); 688 dialog.show(); 689 } 690 break; 691 } 692 break; 693 //TODO: more connectivity feedback 694 default: 695 //Ignore 696 break; 697 } 698 } 699 } 700 701 /** 702 * Renames/replaces "Next" button when appropriate. "Next" button usually exists in 703 * Wifi setup screens, not in usual wifi settings screen. 704 * 705 * @param connected true when the device is connected to a wifi network. 706 */ 707 private void changeNextButtonState(boolean connected) { 708 if (mInXlSetupWizard) { 709 ((WifiSettingsForSetupWizardXL)getActivity()).changeNextButtonState(connected); 710 } else if (mEnableNextOnConnection && hasNextButton()) { 711 getNextButton().setEnabled(connected); 712 } 713 } 714 715 public void onClick(DialogInterface dialogInterface, int button) { 716 if (mInXlSetupWizard) { 717 if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) { 718 forget(); 719 } else if (button == WifiDialog.BUTTON_SUBMIT) { 720 ((WifiSettingsForSetupWizardXL)getActivity()).onConnectButtonPressed(); 721 } 722 } else { 723 if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) { 724 forget(); 725 } else if (button == WifiDialog.BUTTON_SUBMIT) { 726 submit(mDialog.getController()); 727 } 728 } 729 730 } 731 732 /* package */ void submit(WifiConfigController configController) { 733 int networkSetup = configController.chosenNetworkSetupMethod(); 734 switch(networkSetup) { 735 case WifiConfigController.WPS_PBC: 736 case WifiConfigController.WPS_DISPLAY: 737 case WifiConfigController.WPS_KEYPAD: 738 mWifiManager.startWps(configController.getWpsConfig()); 739 break; 740 case WifiConfigController.MANUAL: 741 final WifiConfiguration config = configController.getConfig(); 742 743 if (config == null) { 744 if (mSelectedAccessPoint != null 745 && !requireKeyStore(mSelectedAccessPoint.getConfig()) 746 && mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) { 747 mWifiManager.connectNetwork(mSelectedAccessPoint.networkId); 748 } 749 } else if (config.networkId != INVALID_NETWORK_ID) { 750 if (mSelectedAccessPoint != null) { 751 saveNetwork(config); 752 } 753 } else { 754 if (configController.isEdit() || requireKeyStore(config)) { 755 saveNetwork(config); 756 } else { 757 mWifiManager.connectNetwork(config); 758 } 759 } 760 break; 761 } 762 763 if (mWifiManager.isWifiEnabled()) { 764 mScanner.resume(); 765 } 766 updateAccessPoints(); 767 } 768 769 private void saveNetwork(WifiConfiguration config) { 770 if (mInXlSetupWizard) { 771 ((WifiSettingsForSetupWizardXL)getActivity()).onSaveNetwork(config); 772 } else { 773 mWifiManager.saveNetwork(config); 774 } 775 } 776 777 /* package */ void forget() { 778 mWifiManager.forgetNetwork(mSelectedAccessPoint.networkId); 779 780 if (mWifiManager.isWifiEnabled()) { 781 mScanner.resume(); 782 } 783 updateAccessPoints(); 784 785 // We need to rename/replace "Next" button in wifi setup context. 786 changeNextButtonState(false); 787 } 788 789 /** 790 * Refreshes acccess points and ask Wifi module to scan networks again. 791 */ 792 /* package */ void refreshAccessPoints() { 793 if (mWifiManager.isWifiEnabled()) { 794 mScanner.resume(); 795 } 796 797 getPreferenceScreen().removeAll(); 798 } 799 800 /** 801 * Called when "add network" button is pressed. 802 */ 803 /* package */ void onAddNetworkPressed() { 804 // No exact access point is selected. 805 mSelectedAccessPoint = null; 806 showConfigUi(null, true); 807 } 808 809 /* package */ int getAccessPointsCount() { 810 final boolean wifiIsEnabled = mWifiManager.isWifiEnabled(); 811 if (wifiIsEnabled) { 812 return getPreferenceScreen().getPreferenceCount(); 813 } else { 814 return 0; 815 } 816 } 817 818 /** 819 * Requests wifi module to pause wifi scan. May be ignored when the module is disabled. 820 */ 821 /* package */ void pauseWifiScan() { 822 if (mWifiManager.isWifiEnabled()) { 823 mScanner.pause(); 824 } 825 } 826 827 /** 828 * Requests wifi module to resume wifi scan. May be ignored when the module is disabled. 829 */ 830 /* package */ void resumeWifiScan() { 831 if (mWifiManager.isWifiEnabled()) { 832 mScanner.resume(); 833 } 834 } 835} 836