WifiSettings.java revision aef794a2894e996fafa17097744a2bab75eb680d
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; 20import static android.os.UserManager.DISALLOW_CONFIG_WIFI; 21 22import android.app.Activity; 23import android.app.Dialog; 24import android.content.Context; 25import android.content.DialogInterface; 26import android.content.Intent; 27import android.content.res.Resources; 28import android.content.res.TypedArray; 29import android.graphics.drawable.Drawable; 30import android.net.ConnectivityManager; 31import android.net.NetworkInfo; 32import android.net.NetworkInfo.State; 33import android.net.wifi.WifiConfiguration; 34import android.net.wifi.WifiManager; 35import android.net.wifi.WpsInfo; 36import android.nfc.NfcAdapter; 37import android.os.Bundle; 38import android.preference.Preference; 39import android.preference.PreferenceScreen; 40import android.text.Spannable; 41import android.text.style.TextAppearanceSpan; 42import android.util.Log; 43import android.view.ContextMenu; 44import android.view.ContextMenu.ContextMenuInfo; 45import android.view.Gravity; 46import android.view.Menu; 47import android.view.MenuInflater; 48import android.view.MenuItem; 49import android.view.View; 50import android.widget.AdapterView.AdapterContextMenuInfo; 51import android.widget.TextView; 52import android.widget.TextView.BufferType; 53import android.widget.Toast; 54 55import com.android.internal.logging.MetricsLogger; 56import com.android.settings.LinkifyUtils; 57import com.android.settings.R; 58import com.android.settings.RestrictedSettingsFragment; 59import com.android.settings.SettingsActivity; 60import com.android.settings.location.ScanningSettings; 61import com.android.settings.search.BaseSearchIndexProvider; 62import com.android.settings.search.Indexable; 63import com.android.settings.search.SearchIndexableRaw; 64import com.android.settingslib.wifi.AccessPoint; 65import com.android.settingslib.wifi.AccessPoint.AccessPointListener; 66import com.android.settingslib.wifi.WifiTracker; 67 68import java.util.ArrayList; 69import java.util.Collection; 70import java.util.List; 71 72/** 73 * Two types of UI are provided here. 74 * 75 * The first is for "usual Settings", appearing as any other Setup fragment. 76 * 77 * The second is for Setup Wizard, with a simplified interface that hides the action bar 78 * and menus. 79 */ 80public class WifiSettings extends RestrictedSettingsFragment 81 implements DialogInterface.OnClickListener, Indexable, WifiTracker.WifiListener, 82 AccessPointListener { 83 84 private static final String TAG = "WifiSettings"; 85 86 /* package */ static final int MENU_ID_WPS_PBC = Menu.FIRST; 87 private static final int MENU_ID_WPS_PIN = Menu.FIRST + 1; 88 private static final int MENU_ID_SAVED_NETWORK = Menu.FIRST + 2; 89 /* package */ static final int MENU_ID_ADD_NETWORK = Menu.FIRST + 3; 90 private static final int MENU_ID_ADVANCED = Menu.FIRST + 4; 91 private static final int MENU_ID_SCAN = Menu.FIRST + 5; 92 private static final int MENU_ID_CONNECT = Menu.FIRST + 6; 93 private static final int MENU_ID_FORGET = Menu.FIRST + 7; 94 private static final int MENU_ID_MODIFY = Menu.FIRST + 8; 95 private static final int MENU_ID_WRITE_NFC = Menu.FIRST + 9; 96 97 public static final int WIFI_DIALOG_ID = 1; 98 /* package */ static final int WPS_PBC_DIALOG_ID = 2; 99 private static final int WPS_PIN_DIALOG_ID = 3; 100 private static final int WRITE_NFC_DIALOG_ID = 6; 101 102 // Instance state keys 103 private static final String SAVE_DIALOG_EDIT_MODE = "edit_mode"; 104 private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state"; 105 private static final String SAVED_WIFI_NFC_DIALOG_STATE = "wifi_nfc_dlg_state"; 106 107 private static boolean savedNetworksExist; 108 109 protected WifiManager mWifiManager; 110 private WifiManager.ActionListener mConnectListener; 111 private WifiManager.ActionListener mSaveListener; 112 private WifiManager.ActionListener mForgetListener; 113 114 private WifiEnabler mWifiEnabler; 115 // An access point being editted is stored here. 116 private AccessPoint mSelectedAccessPoint; 117 118 private WifiDialog mDialog; 119 private WriteWifiConfigToNfcDialog mWifiToNfcDialog; 120 121 private TextView mEmptyView; 122 123 // this boolean extra specifies whether to disable the Next button when not connected. Used by 124 // account creation outside of setup wizard. 125 private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect"; 126 // This string extra specifies a network to open the connect dialog on, so the user can enter 127 // network credentials. This is used by quick settings for secured networks. 128 private static final String EXTRA_START_CONNECT_SSID = "wifi_start_connect_ssid"; 129 130 // should Next button only be enabled when we have a connection? 131 private boolean mEnableNextOnConnection; 132 133 // Save the dialog details 134 private boolean mDlgEdit; 135 private AccessPoint mDlgAccessPoint; 136 private Bundle mAccessPointSavedState; 137 private Bundle mWifiNfcDialogSavedState; 138 139 private WifiTracker mWifiTracker; 140 141 /* End of "used in Wifi Setup context" */ 142 143 public WifiSettings() { 144 super(DISALLOW_CONFIG_WIFI); 145 } 146 147 @Override 148 public void onActivityCreated(Bundle savedInstanceState) { 149 super.onActivityCreated(savedInstanceState); 150 151 mWifiTracker = new WifiTracker(getActivity(), this, true, true); 152 mWifiManager = mWifiTracker.getManager(); 153 154 mConnectListener = new WifiManager.ActionListener() { 155 @Override 156 public void onSuccess() { 157 } 158 @Override 159 public void onFailure(int reason) { 160 Activity activity = getActivity(); 161 if (activity != null) { 162 Toast.makeText(activity, 163 R.string.wifi_failed_connect_message, 164 Toast.LENGTH_SHORT).show(); 165 } 166 } 167 }; 168 169 mSaveListener = new WifiManager.ActionListener() { 170 @Override 171 public void onSuccess() { 172 } 173 @Override 174 public void onFailure(int reason) { 175 Activity activity = getActivity(); 176 if (activity != null) { 177 Toast.makeText(activity, 178 R.string.wifi_failed_save_message, 179 Toast.LENGTH_SHORT).show(); 180 } 181 } 182 }; 183 184 mForgetListener = new WifiManager.ActionListener() { 185 @Override 186 public void onSuccess() { 187 } 188 @Override 189 public void onFailure(int reason) { 190 Activity activity = getActivity(); 191 if (activity != null) { 192 Toast.makeText(activity, 193 R.string.wifi_failed_forget_message, 194 Toast.LENGTH_SHORT).show(); 195 } 196 } 197 }; 198 199 if (savedInstanceState != null) { 200 mDlgEdit = savedInstanceState.getBoolean(SAVE_DIALOG_EDIT_MODE); 201 if (savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) { 202 mAccessPointSavedState = 203 savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE); 204 } 205 206 if (savedInstanceState.containsKey(SAVED_WIFI_NFC_DIALOG_STATE)) { 207 mWifiNfcDialogSavedState = 208 savedInstanceState.getBundle(SAVED_WIFI_NFC_DIALOG_STATE); 209 } 210 } 211 212 // if we're supposed to enable/disable the Next button based on our current connection 213 // state, start it off in the right state 214 Intent intent = getActivity().getIntent(); 215 mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false); 216 217 if (mEnableNextOnConnection) { 218 if (hasNextButton()) { 219 final ConnectivityManager connectivity = (ConnectivityManager) 220 getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); 221 if (connectivity != null) { 222 NetworkInfo info = connectivity.getNetworkInfo( 223 ConnectivityManager.TYPE_WIFI); 224 changeNextButtonState(info.isConnected()); 225 } 226 } 227 } 228 229 addPreferencesFromResource(R.xml.wifi_settings); 230 231 mEmptyView = initEmptyView(); 232 registerForContextMenu(getListView()); 233 setHasOptionsMenu(true); 234 235 if (intent.hasExtra(EXTRA_START_CONNECT_SSID)) { 236 String ssid = intent.getStringExtra(EXTRA_START_CONNECT_SSID); 237 onAccessPointsChanged(); 238 PreferenceScreen preferenceScreen = getPreferenceScreen(); 239 for (int i = 0; i < preferenceScreen.getPreferenceCount(); i++) { 240 Preference preference = preferenceScreen.getPreference(i); 241 if (preference instanceof AccessPointPreference) { 242 AccessPoint accessPoint = ((AccessPointPreference) preference).getAccessPoint(); 243 if (ssid.equals(accessPoint.getSsid()) && !accessPoint.isSaved() 244 && accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) { 245 onPreferenceTreeClick(preferenceScreen, preference); 246 break; 247 } 248 } 249 } 250 } 251 } 252 253 @Override 254 public void onDestroyView() { 255 super.onDestroyView(); 256 257 if (mWifiEnabler != null) { 258 mWifiEnabler.teardownSwitchBar(); 259 } 260 } 261 262 @Override 263 public void onStart() { 264 super.onStart(); 265 266 // On/off switch is hidden for Setup Wizard (returns null) 267 mWifiEnabler = createWifiEnabler(); 268 } 269 270 /** 271 * @return new WifiEnabler or null (as overridden by WifiSettingsForSetupWizard) 272 */ 273 /* package */ WifiEnabler createWifiEnabler() { 274 final SettingsActivity activity = (SettingsActivity) getActivity(); 275 return new WifiEnabler(activity, activity.getSwitchBar()); 276 } 277 278 @Override 279 public void onResume() { 280 final Activity activity = getActivity(); 281 super.onResume(); 282 if (mWifiEnabler != null) { 283 mWifiEnabler.resume(activity); 284 } 285 286 mWifiTracker.startTracking(); 287 } 288 289 @Override 290 public void onPause() { 291 super.onPause(); 292 if (mWifiEnabler != null) { 293 mWifiEnabler.pause(); 294 } 295 296 mWifiTracker.stopTracking(); 297 } 298 299 @Override 300 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 301 // If the user is not allowed to configure wifi, do not show the menu. 302 if (isUiRestricted()) return; 303 304 addOptionsMenuItems(menu); 305 super.onCreateOptionsMenu(menu, inflater); 306 } 307 308 /** 309 * @param menu 310 */ 311 void addOptionsMenuItems(Menu menu) { 312 final boolean wifiIsEnabled = mWifiTracker.isWifiEnabled(); 313 TypedArray ta = getActivity().getTheme().obtainStyledAttributes( 314 new int[] {R.attr.ic_menu_add, R.attr.ic_wps}); 315 menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network) 316 .setIcon(ta.getDrawable(0)) 317 .setEnabled(wifiIsEnabled) 318 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); 319 if (savedNetworksExist) { 320 menu.add(Menu.NONE, MENU_ID_SAVED_NETWORK, 0, R.string.wifi_saved_access_points_label) 321 .setIcon(ta.getDrawable(0)) 322 .setEnabled(wifiIsEnabled) 323 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); 324 } 325 menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.menu_stats_refresh) 326 .setEnabled(wifiIsEnabled) 327 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); 328 menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced) 329 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); 330 ta.recycle(); 331 } 332 333 @Override 334 protected int getMetricsCategory() { 335 return MetricsLogger.WIFI; 336 } 337 338 @Override 339 public void onSaveInstanceState(Bundle outState) { 340 super.onSaveInstanceState(outState); 341 342 // If the dialog is showing, save its state. 343 if (mDialog != null && mDialog.isShowing()) { 344 outState.putBoolean(SAVE_DIALOG_EDIT_MODE, mDlgEdit); 345 if (mDlgAccessPoint != null) { 346 mAccessPointSavedState = new Bundle(); 347 mDlgAccessPoint.saveWifiState(mAccessPointSavedState); 348 outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState); 349 } 350 } 351 352 if (mWifiToNfcDialog != null && mWifiToNfcDialog.isShowing()) { 353 Bundle savedState = new Bundle(); 354 mWifiToNfcDialog.saveState(savedState); 355 outState.putBundle(SAVED_WIFI_NFC_DIALOG_STATE, savedState); 356 } 357 } 358 359 @Override 360 public boolean onOptionsItemSelected(MenuItem item) { 361 // If the user is not allowed to configure wifi, do not handle menu selections. 362 if (isUiRestricted()) return false; 363 364 switch (item.getItemId()) { 365 case MENU_ID_WPS_PBC: 366 showDialog(WPS_PBC_DIALOG_ID); 367 return true; 368 /* 369 case MENU_ID_P2P: 370 if (getActivity() instanceof SettingsActivity) { 371 ((SettingsActivity) getActivity()).startPreferencePanel( 372 WifiP2pSettings.class.getCanonicalName(), 373 null, 374 R.string.wifi_p2p_settings_title, null, 375 this, 0); 376 } else { 377 startFragment(this, WifiP2pSettings.class.getCanonicalName(), 378 R.string.wifi_p2p_settings_title, -1, null); 379 } 380 return true; 381 */ 382 case MENU_ID_WPS_PIN: 383 showDialog(WPS_PIN_DIALOG_ID); 384 return true; 385 case MENU_ID_SCAN: 386 MetricsLogger.action(getActivity(), MetricsLogger.ACTION_WIFI_FORCE_SCAN); 387 mWifiTracker.forceScan(); 388 return true; 389 case MENU_ID_ADD_NETWORK: 390 if (mWifiTracker.isWifiEnabled()) { 391 onAddNetworkPressed(); 392 } 393 return true; 394 case MENU_ID_SAVED_NETWORK: 395 if (getActivity() instanceof SettingsActivity) { 396 ((SettingsActivity) getActivity()).startPreferencePanel( 397 SavedAccessPointsWifiSettings.class.getCanonicalName(), null, 398 R.string.wifi_saved_access_points_titlebar, null, this, 0); 399 } else { 400 startFragment(this, SavedAccessPointsWifiSettings.class.getCanonicalName(), 401 R.string.wifi_saved_access_points_titlebar, 402 -1 /* Do not request a result */, null); 403 } 404 return true; 405 case MENU_ID_ADVANCED: 406 if (getActivity() instanceof SettingsActivity) { 407 ((SettingsActivity) getActivity()).startPreferencePanel( 408 AdvancedWifiSettings.class.getCanonicalName(), null, 409 R.string.wifi_advanced_titlebar, null, this, 0); 410 } else { 411 startFragment(this, AdvancedWifiSettings.class.getCanonicalName(), 412 R.string.wifi_advanced_titlebar, -1 /* Do not request a results */, 413 null); 414 } 415 return true; 416 } 417 return super.onOptionsItemSelected(item); 418 } 419 420 @Override 421 public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) { 422 if (info instanceof AdapterContextMenuInfo) { 423 Preference preference = (Preference) getListView().getItemAtPosition( 424 ((AdapterContextMenuInfo) info).position); 425 426 if (preference instanceof AccessPointPreference) { 427 mSelectedAccessPoint = ((AccessPointPreference) preference).getAccessPoint(); 428 menu.setHeaderTitle(mSelectedAccessPoint.getSsid()); 429 if (mSelectedAccessPoint.isConnectable()) { 430 menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect); 431 } 432 433 if (mSelectedAccessPoint.isSaved() || mSelectedAccessPoint.isEphemeral()) { 434 // Allow forgetting a network if either the network is saved or ephemerally 435 // connected. (In the latter case, "forget" blacklists the network so it won't 436 // be used again, ephemerally). 437 menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget); 438 } 439 if (mSelectedAccessPoint.isSaved()) { 440 menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify); 441 NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity()); 442 if (nfcAdapter != null && nfcAdapter.isEnabled() && 443 mSelectedAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) { 444 // Only allow writing of NFC tags for password-protected networks. 445 menu.add(Menu.NONE, MENU_ID_WRITE_NFC, 0, R.string.wifi_menu_write_to_nfc); 446 } 447 } 448 } 449 } 450 } 451 452 @Override 453 public boolean onContextItemSelected(MenuItem item) { 454 if (mSelectedAccessPoint == null) { 455 return super.onContextItemSelected(item); 456 } 457 switch (item.getItemId()) { 458 case MENU_ID_CONNECT: { 459 if (mSelectedAccessPoint.isSaved()) { 460 connect(mSelectedAccessPoint.getConfig()); 461 } else if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) { 462 /** Bypass dialog for unsecured networks */ 463 mSelectedAccessPoint.generateOpenNetworkConfig(); 464 connect(mSelectedAccessPoint.getConfig()); 465 } else { 466 showDialog(mSelectedAccessPoint, true); 467 } 468 return true; 469 } 470 case MENU_ID_FORGET: { 471 forget(); 472 return true; 473 } 474 case MENU_ID_MODIFY: { 475 showDialog(mSelectedAccessPoint, true); 476 return true; 477 } 478 case MENU_ID_WRITE_NFC: 479 showDialog(WRITE_NFC_DIALOG_ID); 480 return true; 481 482 } 483 return super.onContextItemSelected(item); 484 } 485 486 @Override 487 public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) { 488 if (preference instanceof AccessPointPreference) { 489 mSelectedAccessPoint = ((AccessPointPreference) preference).getAccessPoint(); 490 /** Bypass dialog for unsecured, unsaved, and inactive networks */ 491 if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE && 492 !mSelectedAccessPoint.isSaved() && !mSelectedAccessPoint.isActive()) { 493 mSelectedAccessPoint.generateOpenNetworkConfig(); 494 if (!savedNetworksExist) { 495 savedNetworksExist = true; 496 getActivity().invalidateOptionsMenu(); 497 } 498 connect(mSelectedAccessPoint.getConfig()); 499 } else { 500 showDialog(mSelectedAccessPoint, false); 501 } 502 } else { 503 return super.onPreferenceTreeClick(screen, preference); 504 } 505 return true; 506 } 507 508 private void showDialog(AccessPoint accessPoint, boolean edit) { 509 if (mDialog != null) { 510 removeDialog(WIFI_DIALOG_ID); 511 mDialog = null; 512 } 513 514 // Save the access point and edit mode 515 mDlgAccessPoint = accessPoint; 516 mDlgEdit = edit; 517 518 showDialog(WIFI_DIALOG_ID); 519 } 520 521 @Override 522 public Dialog onCreateDialog(int dialogId) { 523 switch (dialogId) { 524 case WIFI_DIALOG_ID: 525 AccessPoint ap = mDlgAccessPoint; // For manual launch 526 if (ap == null) { // For re-launch from saved state 527 if (mAccessPointSavedState != null) { 528 ap = new AccessPoint(getActivity(), mAccessPointSavedState); 529 // For repeated orientation changes 530 mDlgAccessPoint = ap; 531 // Reset the saved access point data 532 mAccessPointSavedState = null; 533 } 534 } 535 // If it's null, fine, it's for Add Network 536 mSelectedAccessPoint = ap; 537 mDialog = new WifiDialog(getActivity(), this, ap, mDlgEdit); 538 return mDialog; 539 case WPS_PBC_DIALOG_ID: 540 return new WpsDialog(getActivity(), WpsInfo.PBC); 541 case WPS_PIN_DIALOG_ID: 542 return new WpsDialog(getActivity(), WpsInfo.DISPLAY); 543 case WRITE_NFC_DIALOG_ID: 544 if (mSelectedAccessPoint != null) { 545 mWifiToNfcDialog = new WriteWifiConfigToNfcDialog( 546 getActivity(), mSelectedAccessPoint.getConfig().networkId, 547 mSelectedAccessPoint.getSecurity(), 548 mWifiManager); 549 } else if (mWifiNfcDialogSavedState != null) { 550 mWifiToNfcDialog = new WriteWifiConfigToNfcDialog( 551 getActivity(), mWifiNfcDialogSavedState, mWifiManager); 552 } 553 554 return mWifiToNfcDialog; 555 } 556 return super.onCreateDialog(dialogId); 557 } 558 559 /** 560 * Shows the latest access points available with supplemental information like 561 * the strength of network and the security for it. 562 */ 563 @Override 564 public void onAccessPointsChanged() { 565 // Safeguard from some delayed event handling 566 if (getActivity() == null) return; 567 568 if (isUiRestricted()) { 569 addMessagePreference(R.string.wifi_empty_list_user_restricted); 570 return; 571 } 572 final int wifiState = mWifiManager.getWifiState(); 573 574 switch (wifiState) { 575 case WifiManager.WIFI_STATE_ENABLED: 576 // AccessPoints are automatically sorted with TreeSet. 577 final Collection<AccessPoint> accessPoints = 578 mWifiTracker.getAccessPoints(); 579 getPreferenceScreen().removeAll(); 580 if (accessPoints.size() == 0) { 581 addMessagePreference(R.string.wifi_empty_list_wifi_on); 582 } 583 584 for (AccessPoint accessPoint : accessPoints) { 585 // Ignore access points that are out of range. 586 if (accessPoint.getLevel() != -1) { 587 AccessPointPreference preference = new AccessPointPreference(accessPoint, 588 getActivity()); 589 590 getPreferenceScreen().addPreference(preference); 591 accessPoint.setListener(this); 592 } 593 } 594 break; 595 596 case WifiManager.WIFI_STATE_ENABLING: 597 getPreferenceScreen().removeAll(); 598 break; 599 600 case WifiManager.WIFI_STATE_DISABLING: 601 addMessagePreference(R.string.wifi_stopping); 602 break; 603 604 case WifiManager.WIFI_STATE_DISABLED: 605 setOffMessage(); 606 break; 607 } 608 // Update "Saved Networks" menu option. 609 if (savedNetworksExist != mWifiTracker.doSavedNetworksExist()) { 610 savedNetworksExist = !savedNetworksExist; 611 getActivity().invalidateOptionsMenu(); 612 } 613 } 614 615 protected TextView initEmptyView() { 616 TextView emptyView = (TextView) getActivity().findViewById(android.R.id.empty); 617 emptyView.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); 618 getListView().setEmptyView(emptyView); 619 return emptyView; 620 } 621 622 private void setOffMessage() { 623 if (mEmptyView == null) { 624 return; 625 } 626 627 final CharSequence briefText = getText(R.string.wifi_empty_list_wifi_off); 628 if (isUiRestricted()) { 629 // Show only the brief text if the user is not allowed to configure scanning settings. 630 mEmptyView.setText(briefText, BufferType.SPANNABLE); 631 } else { 632 // Append the description of scanning settings with link. 633 final StringBuilder contentBuilder = new StringBuilder(); 634 contentBuilder.append(briefText); 635 contentBuilder.append("\n\n"); 636 contentBuilder.append(getText(R.string.wifi_scan_notify_text)); 637 LinkifyUtils.linkify(mEmptyView, contentBuilder, new LinkifyUtils.OnClickListener() { 638 @Override 639 public void onClick() { 640 final SettingsActivity activity = 641 (SettingsActivity) WifiSettings.this.getActivity(); 642 activity.startPreferencePanel(ScanningSettings.class.getName(), null, 643 R.string.location_scanning_screen_title, null, null, 0); 644 } 645 }); 646 } 647 // Embolden and enlarge the brief description anyway. 648 Spannable boldSpan = (Spannable) mEmptyView.getText(); 649 boldSpan.setSpan( 650 new TextAppearanceSpan(getActivity(), android.R.style.TextAppearance_Medium), 0, 651 briefText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 652 getPreferenceScreen().removeAll(); 653 } 654 655 private void addMessagePreference(int messageId) { 656 if (mEmptyView != null) mEmptyView.setText(messageId); 657 getPreferenceScreen().removeAll(); 658 } 659 660 @Override 661 public void onWifiStateChanged(int state) { 662 Activity activity = getActivity(); 663 if (activity != null) { 664 activity.invalidateOptionsMenu(); 665 } 666 667 switch (state) { 668 case WifiManager.WIFI_STATE_ENABLING: 669 addMessagePreference(R.string.wifi_starting); 670 break; 671 672 case WifiManager.WIFI_STATE_DISABLED: 673 setOffMessage(); 674 break; 675 } 676 } 677 678 @Override 679 public void onConnectedChanged() { 680 changeNextButtonState(mWifiTracker.isConnected()); 681 } 682 683 /** 684 * Renames/replaces "Next" button when appropriate. "Next" button usually exists in 685 * Wifi setup screens, not in usual wifi settings screen. 686 * 687 * @param enabled true when the device is connected to a wifi network. 688 */ 689 private void changeNextButtonState(boolean enabled) { 690 if (mEnableNextOnConnection && hasNextButton()) { 691 getNextButton().setEnabled(enabled); 692 } 693 } 694 695 @Override 696 public void onClick(DialogInterface dialogInterface, int button) { 697 if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) { 698 forget(); 699 } else if (button == WifiDialog.BUTTON_SUBMIT) { 700 if (mDialog != null) { 701 submit(mDialog.getController()); 702 } 703 } 704 } 705 706 /* package */ void submit(WifiConfigController configController) { 707 708 final WifiConfiguration config = configController.getConfig(); 709 710 if (config == null) { 711 if (mSelectedAccessPoint != null 712 && mSelectedAccessPoint.isSaved()) { 713 connect(mSelectedAccessPoint.getConfig()); 714 } 715 } else if (config.networkId != INVALID_NETWORK_ID) { 716 if (mSelectedAccessPoint != null) { 717 mWifiManager.save(config, mSaveListener); 718 } 719 } else { 720 if (configController.isEdit()) { 721 mWifiManager.save(config, mSaveListener); 722 } else { 723 connect(config); 724 } 725 } 726 727 mWifiTracker.resumeScanning(); 728 } 729 730 /* package */ void forget() { 731 MetricsLogger.action(getActivity(), MetricsLogger.ACTION_WIFI_FORGET); 732 if (!mSelectedAccessPoint.isSaved()) { 733 if (mSelectedAccessPoint.getNetworkInfo().getState() != State.DISCONNECTED) { 734 // Network is active but has no network ID - must be ephemeral. 735 mWifiManager.disableEphemeralNetwork( 736 AccessPoint.convertToQuotedString(mSelectedAccessPoint.getSsid())); 737 } else { 738 // Should not happen, but a monkey seems to trigger it 739 Log.e(TAG, "Failed to forget invalid network " + mSelectedAccessPoint.getConfig()); 740 return; 741 } 742 } else { 743 mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId, mForgetListener); 744 } 745 746 mWifiTracker.resumeScanning(); 747 748 // We need to rename/replace "Next" button in wifi setup context. 749 changeNextButtonState(false); 750 } 751 752 protected void connect(final WifiConfiguration config) { 753 MetricsLogger.action(getActivity(), MetricsLogger.ACTION_WIFI_CONNECT); 754 mWifiManager.connect(config, mConnectListener); 755 } 756 757 protected void connect(final int networkId) { 758 MetricsLogger.action(getActivity(), MetricsLogger.ACTION_WIFI_CONNECT); 759 mWifiManager.connect(networkId, mConnectListener); 760 } 761 762 /** 763 * Refreshes acccess points and ask Wifi module to scan networks again. 764 */ 765 /* package */ void refreshAccessPoints() { 766 mWifiTracker.resumeScanning(); 767 768 getPreferenceScreen().removeAll(); 769 } 770 771 /** 772 * Called when "add network" button is pressed. 773 */ 774 /* package */ void onAddNetworkPressed() { 775 MetricsLogger.action(getActivity(), MetricsLogger.ACTION_WIFI_ADD_NETWORK); 776 // No exact access point is selected. 777 mSelectedAccessPoint = null; 778 showDialog(null, true); 779 } 780 781 /* package */ int getAccessPointsCount() { 782 final boolean wifiIsEnabled = mWifiTracker.isWifiEnabled(); 783 if (wifiIsEnabled) { 784 return getPreferenceScreen().getPreferenceCount(); 785 } else { 786 return 0; 787 } 788 } 789 790 /** 791 * Requests wifi module to pause wifi scan. May be ignored when the module is disabled. 792 */ 793 /* package */ void pauseWifiScan() { 794 mWifiTracker.pauseScanning(); 795 } 796 797 /** 798 * Requests wifi module to resume wifi scan. May be ignored when the module is disabled. 799 */ 800 /* package */ void resumeWifiScan() { 801 mWifiTracker.resumeScanning(); 802 } 803 804 @Override 805 protected int getHelpResource() { 806 return R.string.help_url_wifi; 807 } 808 809 @Override 810 public void onAccessPointChanged(AccessPoint accessPoint) { 811 ((AccessPointPreference) accessPoint.getTag()).refresh(); 812 } 813 814 @Override 815 public void onLevelChanged(AccessPoint accessPoint) { 816 ((AccessPointPreference) accessPoint.getTag()).onLevelChanged(); 817 } 818 819 public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 820 new BaseSearchIndexProvider() { 821 @Override 822 public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) { 823 final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>(); 824 final Resources res = context.getResources(); 825 826 // Add fragment title 827 SearchIndexableRaw data = new SearchIndexableRaw(context); 828 data.title = res.getString(R.string.wifi_settings); 829 data.screenTitle = res.getString(R.string.wifi_settings); 830 data.keywords = res.getString(R.string.keywords_wifi); 831 result.add(data); 832 833 // Add saved Wi-Fi access points 834 final Collection<AccessPoint> accessPoints = 835 WifiTracker.getCurrentAccessPoints(context, true, false); 836 for (AccessPoint accessPoint : accessPoints) { 837 data = new SearchIndexableRaw(context); 838 data.title = accessPoint.getSsid(); 839 data.screenTitle = res.getString(R.string.wifi_settings); 840 data.enabled = enabled; 841 result.add(data); 842 } 843 844 return result; 845 } 846 }; 847} 848