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 android.app.Activity; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.pm.ActivityInfo; 23 import android.net.NetworkInfo.DetailedState; 24 import android.net.wifi.WifiConfiguration; 25 import android.net.wifi.WifiManager; 26 import android.os.Bundle; 27 import android.os.Handler; 28 import android.os.Message; 29 import android.preference.PreferenceScreen; 30 import android.text.TextUtils; 31 import android.util.Log; 32 import android.view.View; 33 import android.view.View.OnClickListener; 34 import android.view.ViewGroup; 35 import android.view.Window; 36 import android.view.inputmethod.InputMethodManager; 37 import android.widget.Button; 38 import android.widget.ProgressBar; 39 import android.widget.TextView; 40 41 import com.android.internal.util.AsyncChannel; 42 import com.android.settings.R; 43 44 import java.util.Collection; 45 import java.util.EnumMap; 46 import java.util.List; 47 48 /** 49 * WifiSetings Activity specific for SetupWizard with X-Large screen size. 50 */ 51 public class WifiSettingsForSetupWizardXL extends Activity implements OnClickListener { 52 private static final String TAG = "SetupWizard"; 53 private static final boolean DEBUG = true; 54 55 // lock orientation into landscape or portrait 56 private static final String EXTRA_PREFS_LANDSCAPE_LOCK = "extra_prefs_landscape_lock"; 57 private static final String EXTRA_PREFS_PORTRAIT_LOCK = "extra_prefs_portrait_lock"; 58 59 private static final EnumMap<DetailedState, DetailedState> sNetworkStateMap = 60 new EnumMap<DetailedState, DetailedState>(DetailedState.class); 61 62 static { 63 sNetworkStateMap.put(DetailedState.IDLE, DetailedState.DISCONNECTED); 64 sNetworkStateMap.put(DetailedState.SCANNING, DetailedState.SCANNING); 65 sNetworkStateMap.put(DetailedState.CONNECTING, DetailedState.CONNECTING); 66 sNetworkStateMap.put(DetailedState.AUTHENTICATING, DetailedState.CONNECTING); 67 sNetworkStateMap.put(DetailedState.OBTAINING_IPADDR, DetailedState.CONNECTING); 68 sNetworkStateMap.put(DetailedState.CONNECTED, DetailedState.CONNECTED); 69 sNetworkStateMap.put(DetailedState.SUSPENDED, DetailedState.SUSPENDED); // ? 70 sNetworkStateMap.put(DetailedState.DISCONNECTING, DetailedState.DISCONNECTED); 71 sNetworkStateMap.put(DetailedState.DISCONNECTED, DetailedState.DISCONNECTED); 72 sNetworkStateMap.put(DetailedState.FAILED, DetailedState.FAILED); 73 } 74 75 private WifiSettings mWifiSettings; 76 private WifiManager mWifiManager; 77 78 /** Used for resizing a padding above title. Hiden when software keyboard is shown. */ 79 private View mTopPadding; 80 81 /** Used for resizing a padding of main content. Hiden when software keyboard is shown. */ 82 private View mContentPadding; 83 84 private TextView mTitleView; 85 /** 86 * The name of a network currently connecting, or trying to connect. 87 * This may be empty ("") at first, and updated when configuration is changed. 88 */ 89 private CharSequence mNetworkName = ""; 90 private CharSequence mEditingTitle; 91 92 private ProgressBar mProgressBar; 93 private View mTopDividerNoProgress; 94 /** 95 * Used for resizing a padding between WifiSettings preference and bottom bar when 96 * ProgressBar is visible as a top divider. 97 */ 98 private View mBottomPadding; 99 100 private Button mAddNetworkButton; 101 private Button mRefreshButton; 102 private Button mSkipOrNextButton; 103 private Button mBackButton; 104 105 private Button mConnectButton; 106 107 /** 108 * View enclosing {@link WifiSettings}. 109 */ 110 private View mWifiSettingsFragmentLayout; 111 private View mConnectingStatusLayout; 112 private TextView mConnectingStatusView; 113 114 /* 115 * States of current screen, which should be saved and restored when Activity is relaunched 116 * with orientation change, etc. 117 */ 118 private static final int SCREEN_STATE_DISCONNECTED = 0; 119 private static final int SCREEN_STATE_EDITING = 1; 120 private static final int SCREEN_STATE_CONNECTING = 2; 121 private static final int SCREEN_STATE_CONNECTED = 3; 122 123 /** Current screen state. */ 124 private int mScreenState = SCREEN_STATE_DISCONNECTED; 125 126 private WifiConfigUiForSetupWizardXL mWifiConfig; 127 128 private InputMethodManager mInputMethodManager; 129 130 /** 131 * Previous network connection state reported by main Wifi module. 132 * 133 * Note that we don't use original {@link DetailedState} object but simplified one translated 134 * using sNetworkStateMap. 135 */ 136 private DetailedState mPreviousNetworkState = DetailedState.DISCONNECTED; 137 138 @Override 139 public void onCreate(Bundle savedInstanceState) { 140 super.onCreate(savedInstanceState); 141 requestWindowFeature(Window.FEATURE_NO_TITLE); 142 setContentView(R.layout.wifi_settings_for_setup_wizard_xl); 143 144 mWifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE); 145 // There's no button here enabling wifi network, so we need to enable it without 146 // users' request. 147 mWifiManager.setWifiEnabled(true); 148 mWifiManager.asyncConnect(this, new WifiServiceHandler()); 149 150 mWifiSettings = 151 (WifiSettings)getFragmentManager().findFragmentById(R.id.wifi_setup_fragment); 152 mInputMethodManager = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); 153 154 initViews(); 155 156 // At first, Wifi module doesn't return SCANNING state (it's too early), so we manually 157 // show it. 158 showScanningState(); 159 } 160 161 private void initViews() { 162 Intent intent = getIntent(); 163 164 if (intent.getBooleanExtra("firstRun", false)) { 165 final View layoutRoot = findViewById(R.id.layout_root); 166 layoutRoot.setSystemUiVisibility(View.STATUS_BAR_DISABLE_BACK); 167 } 168 if (intent.getBooleanExtra(EXTRA_PREFS_LANDSCAPE_LOCK, false)) { 169 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); 170 } 171 if (intent.getBooleanExtra(EXTRA_PREFS_PORTRAIT_LOCK, false)) { 172 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); 173 } 174 175 mTitleView = (TextView)findViewById(R.id.wifi_setup_title); 176 mProgressBar = (ProgressBar)findViewById(R.id.scanning_progress_bar); 177 mProgressBar.setMax(2); 178 mTopDividerNoProgress = findViewById(R.id.top_divider_no_progress); 179 mBottomPadding = findViewById(R.id.bottom_padding); 180 181 mProgressBar.setVisibility(View.VISIBLE); 182 mProgressBar.setIndeterminate(true); 183 mTopDividerNoProgress.setVisibility(View.GONE); 184 185 mAddNetworkButton = (Button)findViewById(R.id.wifi_setup_add_network); 186 mAddNetworkButton.setOnClickListener(this); 187 mRefreshButton = (Button)findViewById(R.id.wifi_setup_refresh_list); 188 mRefreshButton.setOnClickListener(this); 189 mSkipOrNextButton = (Button)findViewById(R.id.wifi_setup_skip_or_next); 190 mSkipOrNextButton.setOnClickListener(this); 191 mConnectButton = (Button)findViewById(R.id.wifi_setup_connect); 192 mConnectButton.setOnClickListener(this); 193 mBackButton = (Button)findViewById(R.id.wifi_setup_cancel); 194 mBackButton.setOnClickListener(this); 195 196 mTopPadding = findViewById(R.id.top_padding); 197 mContentPadding = findViewById(R.id.content_padding); 198 199 mWifiSettingsFragmentLayout = findViewById(R.id.wifi_settings_fragment_layout); 200 mConnectingStatusLayout = findViewById(R.id.connecting_status_layout); 201 mConnectingStatusView = (TextView) findViewById(R.id.connecting_status); 202 } 203 204 private class WifiServiceHandler extends Handler { 205 @Override 206 public void handleMessage(Message msg) { 207 switch (msg.what) { 208 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 209 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 210 //AsyncChannel in msg.obj 211 } else { 212 //AsyncChannel set up failure, ignore 213 Log.e(TAG, "Failed to establish AsyncChannel connection"); 214 } 215 break; 216 default: 217 //Ignore 218 break; 219 } 220 } 221 } 222 223 private void restoreFirstVisibilityState() { 224 showDefaultTitle(); 225 mAddNetworkButton.setVisibility(View.VISIBLE); 226 mRefreshButton.setVisibility(View.VISIBLE); 227 mSkipOrNextButton.setVisibility(View.VISIBLE); 228 mConnectButton.setVisibility(View.GONE); 229 mBackButton.setVisibility(View.GONE); 230 setPaddingVisibility(View.VISIBLE); 231 } 232 233 @Override 234 public void onClick(View view) { 235 hideSoftwareKeyboard(); 236 if (view == mAddNetworkButton) { 237 if (DEBUG) Log.d(TAG, "AddNetwork button pressed"); 238 onAddNetworkButtonPressed(); 239 } else if (view == mRefreshButton) { 240 if (DEBUG) Log.d(TAG, "Refresh button pressed"); 241 refreshAccessPoints(true); 242 } else if (view == mSkipOrNextButton) { 243 if (DEBUG) Log.d(TAG, "Skip/Next button pressed"); 244 if (TextUtils.equals(getString(R.string.wifi_setup_skip), ((Button)view).getText())) { 245 // We don't want to let Wifi enabled when a user press skip without choosing 246 // any access point. 247 mWifiManager.setWifiEnabled(false); 248 // Notify "skip" 249 setResult(RESULT_FIRST_USER); 250 } else { 251 setResult(RESULT_OK); 252 } 253 finish(); 254 } else if (view == mConnectButton) { 255 if (DEBUG) Log.d(TAG, "Connect button pressed"); 256 onConnectButtonPressed(); 257 } else if (view == mBackButton) { 258 if (DEBUG) Log.d(TAG, "Back button pressed"); 259 onBackButtonPressed(); 260 } 261 } 262 263 private void hideSoftwareKeyboard() { 264 if (DEBUG) Log.i(TAG, "Hiding software keyboard."); 265 final View focusedView = getCurrentFocus(); 266 if (focusedView != null) { 267 mInputMethodManager.hideSoftInputFromWindow(focusedView.getWindowToken(), 0); 268 } 269 } 270 271 // Called from WifiSettings 272 /* package */ void updateConnectionState(DetailedState originalState) { 273 final DetailedState state = sNetworkStateMap.get(originalState); 274 275 if (originalState == DetailedState.FAILED) { 276 // We clean up the current connectivity status and let users select another network 277 // if they want. 278 refreshAccessPoints(true); 279 } 280 281 switch (state) { 282 case SCANNING: { 283 if (mScreenState == SCREEN_STATE_DISCONNECTED) { 284 if (mWifiSettings.getAccessPointsCount() == 0) { 285 showScanningState(); 286 } else { 287 showDisconnectedProgressBar(); 288 mWifiSettingsFragmentLayout.setVisibility(View.VISIBLE); 289 mBottomPadding.setVisibility(View.GONE); 290 } 291 } else { 292 showDisconnectedProgressBar(); 293 } 294 break; 295 } 296 case CONNECTING: { 297 if (mScreenState == SCREEN_STATE_CONNECTING) { 298 showConnectingState(); 299 } 300 break; 301 } 302 case CONNECTED: { 303 showConnectedState(); 304 break; 305 } 306 default: // DISCONNECTED, FAILED 307 if (mScreenState != SCREEN_STATE_CONNECTED && 308 mWifiSettings.getAccessPointsCount() > 0) { 309 showDisconnectedState(Summary.get(this, state)); 310 } 311 break; 312 } 313 mPreviousNetworkState = state; 314 } 315 316 private void showDisconnectedState(String stateString) { 317 showDisconnectedProgressBar(); 318 if (mScreenState == SCREEN_STATE_DISCONNECTED && 319 mWifiSettings.getAccessPointsCount() > 0) { 320 mWifiSettingsFragmentLayout.setVisibility(View.VISIBLE); 321 mBottomPadding.setVisibility(View.GONE); 322 } 323 mAddNetworkButton.setEnabled(true); 324 mRefreshButton.setEnabled(true); 325 } 326 327 private void showConnectingState() { 328 mScreenState = SCREEN_STATE_CONNECTING; 329 330 mBackButton.setVisibility(View.VISIBLE); 331 // We save this title and show it when authentication failed. 332 mEditingTitle = mTitleView.getText(); 333 showConnectingTitle(); 334 showConnectingProgressBar(); 335 336 setPaddingVisibility(View.VISIBLE); 337 } 338 339 private void showConnectedState() { 340 // Once we show "connected" screen, we won't change it even when the device becomes 341 // disconnected afterwards. We keep the state unless a user explicitly cancel it 342 // (by pressing "back" button). 343 mScreenState = SCREEN_STATE_CONNECTED; 344 345 hideSoftwareKeyboard(); 346 setPaddingVisibility(View.VISIBLE); 347 348 showConnectedTitle(); 349 showConnectedProgressBar(); 350 351 mWifiSettingsFragmentLayout.setVisibility(View.GONE); 352 mConnectingStatusLayout.setVisibility(View.VISIBLE); 353 354 mConnectingStatusView.setText(R.string.wifi_setup_description_connected); 355 mConnectButton.setVisibility(View.GONE); 356 mAddNetworkButton.setVisibility(View.GONE); 357 mRefreshButton.setVisibility(View.GONE); 358 mBackButton.setVisibility(View.VISIBLE); 359 mBackButton.setText(R.string.wifi_setup_back); 360 mSkipOrNextButton.setVisibility(View.VISIBLE); 361 mSkipOrNextButton.setEnabled(true); 362 } 363 364 private void showDefaultTitle() { 365 mTitleView.setText(getString(R.string.wifi_setup_title)); 366 } 367 368 private void showAddNetworkTitle() { 369 mNetworkName = ""; 370 mTitleView.setText(R.string.wifi_setup_title_add_network); 371 } 372 373 private void showEditingTitle() { 374 if (TextUtils.isEmpty(mNetworkName) && mWifiConfig != null) { 375 if (mWifiConfig.getController() != null && 376 mWifiConfig.getController().getConfig() != null) { 377 mNetworkName = mWifiConfig.getController().getConfig().SSID; 378 } else { 379 Log.w(TAG, "Unexpected null found (WifiController or WifiConfig is null). " + 380 "Ignore them."); 381 } 382 } 383 mTitleView.setText(getString(R.string.wifi_setup_title_editing_network, mNetworkName)); 384 } 385 386 private void showConnectingTitle() { 387 if (TextUtils.isEmpty(mNetworkName) && mWifiConfig != null) { 388 if (mWifiConfig.getController() != null && 389 mWifiConfig.getController().getConfig() != null) { 390 mNetworkName = mWifiConfig.getController().getConfig().SSID; 391 } else { 392 Log.w(TAG, "Unexpected null found (WifiController or WifiConfig is null). " + 393 "Ignore them."); 394 } 395 } 396 mTitleView.setText(getString(R.string.wifi_setup_title_connecting_network, mNetworkName)); 397 } 398 399 private void showConnectedTitle() { 400 if (TextUtils.isEmpty(mNetworkName) && mWifiConfig != null) { 401 if (mWifiConfig.getController() != null && 402 mWifiConfig.getController().getConfig() != null) { 403 mNetworkName = mWifiConfig.getController().getConfig().SSID; 404 } else { 405 Log.w(TAG, "Unexpected null found (WifiController or WifiConfig is null). " + 406 "Ignore them."); 407 } 408 } 409 mTitleView.setText(getString(R.string.wifi_setup_title_connected_network, mNetworkName)); 410 } 411 412 /** 413 * Shows top divider with ProgressBar without defining the state of the ProgressBar. 414 * 415 * @see #showScanningProgressBar() 416 * @see #showConnectedProgressBar() 417 * @see #showConnectingProgressBar() 418 */ 419 private void showTopDividerWithProgressBar() { 420 mProgressBar.setVisibility(View.VISIBLE); 421 mTopDividerNoProgress.setVisibility(View.GONE); 422 mBottomPadding.setVisibility(View.GONE); 423 } 424 425 private void showScanningState() { 426 setPaddingVisibility(View.VISIBLE); 427 mWifiSettingsFragmentLayout.setVisibility(View.GONE); 428 showScanningProgressBar(); 429 } 430 431 private void onAddNetworkButtonPressed() { 432 mWifiSettings.onAddNetworkPressed(); 433 } 434 435 /** 436 * Called when the screen enters wifi configuration UI. UI widget for configuring network 437 * (a.k.a. ConfigPreference) should be taken care of by caller side. 438 * This method should handle buttons' visibility/enabled. 439 * @param selectedAccessPoint AccessPoint object being selected. null when a user pressed 440 * "Add network" button, meaning there's no selected access point. 441 */ 442 /* package */ void showConfigUi(AccessPoint selectedAccessPoint, boolean edit) { 443 mScreenState = SCREEN_STATE_EDITING; 444 445 if (selectedAccessPoint != null && 446 (selectedAccessPoint.security == AccessPoint.SECURITY_WEP || 447 selectedAccessPoint.security == AccessPoint.SECURITY_PSK)) { 448 // We forcibly set edit as true so that users can modify every field if they want, 449 // while config UI doesn't allow them to edit some of them when edit is false 450 // (e.g. password field is hiden when edit==false). 451 edit = true; 452 } 453 454 // We don't want to keep scanning Wifi networks during users' configuring a network. 455 mWifiSettings.pauseWifiScan(); 456 457 mWifiSettingsFragmentLayout.setVisibility(View.GONE); 458 mConnectingStatusLayout.setVisibility(View.GONE); 459 final ViewGroup parent = (ViewGroup)findViewById(R.id.wifi_config_ui); 460 parent.setVisibility(View.VISIBLE); 461 parent.removeAllViews(); 462 mWifiConfig = new WifiConfigUiForSetupWizardXL(this, parent, selectedAccessPoint, edit); 463 464 if (selectedAccessPoint == null) { // "Add network" flow 465 showAddNetworkTitle(); 466 mConnectButton.setVisibility(View.VISIBLE); 467 468 showDisconnectedProgressBar(); 469 showEditingButtonState(); 470 } else if (selectedAccessPoint.security == AccessPoint.SECURITY_NONE) { 471 mNetworkName = selectedAccessPoint.getTitle().toString(); 472 473 // onConnectButtonPressed() will change visibility status. 474 mConnectButton.performClick(); 475 } else { 476 mNetworkName = selectedAccessPoint.getTitle().toString(); 477 showEditingTitle(); 478 showDisconnectedProgressBar(); 479 showEditingButtonState(); 480 if (selectedAccessPoint.security == AccessPoint.SECURITY_EAP) { 481 onEapNetworkSelected(); 482 } else { 483 mConnectButton.setVisibility(View.VISIBLE); 484 485 // WifiConfigController shows Connect button as "Save" when edit==true and a user 486 // tried to connect the network. 487 // In SetupWizard, we just show the button as "Connect" instead. 488 mConnectButton.setText(R.string.wifi_connect); 489 mBackButton.setText(R.string.wifi_setup_cancel); 490 } 491 } 492 } 493 494 /** 495 * Called before security fields are correctly set by {@link WifiConfigController}. 496 * 497 * @param view security field view 498 * @param accessPointSecurity type of security. e.g. AccessPoint.SECURITY_NONE 499 * @return true when it is ok for the caller to init security fields. false when 500 * all security fields are managed by this method, and thus the caller shouldn't touch them. 501 */ 502 /* package */ boolean initSecurityFields(View view, int accessPointSecurity) { 503 // Reset all states tweaked below. 504 view.findViewById(R.id.eap_not_supported).setVisibility(View.GONE); 505 view.findViewById(R.id.eap_not_supported_for_add_network).setVisibility(View.GONE); 506 view.findViewById(R.id.ssid_text).setVisibility(View.VISIBLE); 507 view.findViewById(R.id.ssid_layout).setVisibility(View.VISIBLE); 508 509 if (accessPointSecurity == AccessPoint.SECURITY_EAP) { 510 setPaddingVisibility(View.VISIBLE); 511 hideSoftwareKeyboard(); 512 513 // In SetupWizard for XLarge screen, we don't have enough space for showing 514 // configurations needed for EAP. We instead disable the whole feature there and let 515 // users configure those networks after the setup. 516 if (view.findViewById(R.id.type_ssid).getVisibility() == View.VISIBLE) { 517 view.findViewById(R.id.eap_not_supported_for_add_network) 518 .setVisibility(View.VISIBLE); 519 } else { 520 view.findViewById(R.id.eap_not_supported).setVisibility(View.VISIBLE); 521 } 522 view.findViewById(R.id.security_fields).setVisibility(View.GONE); 523 view.findViewById(R.id.ssid_text).setVisibility(View.GONE); 524 view.findViewById(R.id.ssid_layout).setVisibility(View.GONE); 525 onEapNetworkSelected(); 526 527 // This method did init security fields by itself. The caller must not do it. 528 return false; 529 } 530 531 mConnectButton.setVisibility(View.VISIBLE); 532 setPaddingVisibility(View.GONE); 533 534 // In "add network" flow, we'll see multiple initSecurityFields() calls with different 535 // accessPointSecurity variable. We want to show software keyboard conditionally everytime 536 // when this method is called. 537 if (mWifiConfig != null) { 538 if (accessPointSecurity == AccessPoint.SECURITY_PSK || 539 accessPointSecurity == AccessPoint.SECURITY_WEP) { 540 mWifiConfig.requestFocusAndShowKeyboard(R.id.password); 541 } else { 542 mWifiConfig.requestFocusAndShowKeyboard(R.id.ssid); 543 } 544 } 545 546 // Let the caller init security fields. 547 return true; 548 } 549 550 private void onEapNetworkSelected() { 551 mConnectButton.setVisibility(View.GONE); 552 mBackButton.setText(R.string.wifi_setup_back); 553 } 554 555 private void showEditingButtonState() { 556 mSkipOrNextButton.setVisibility(View.GONE); 557 mAddNetworkButton.setVisibility(View.GONE); 558 mRefreshButton.setVisibility(View.GONE); 559 mBackButton.setVisibility(View.VISIBLE); 560 } 561 562 // May be called when user press "connect" button in WifiDialog 563 /* package */ void onConnectButtonPressed() { 564 mScreenState = SCREEN_STATE_CONNECTING; 565 566 mWifiSettings.submit(mWifiConfig.getController()); 567 568 // updateConnectionState() isn't called soon by the main Wifi module after the user's 569 // "connect" request, and the user still sees "not connected" message for a while, which 570 // looks strange for users though legitimate from the view of the module. 571 // 572 // We instead manually show "connecting" message before the system gets actual 573 // "connecting" message from Wifi module. 574 showConnectingState(); 575 576 // Might be better to delay showing this button. 577 mBackButton.setVisibility(View.VISIBLE); 578 mBackButton.setText(R.string.wifi_setup_back); 579 580 final ViewGroup parent = (ViewGroup)findViewById(R.id.wifi_config_ui); 581 parent.setVisibility(View.GONE); 582 mConnectingStatusLayout.setVisibility(View.VISIBLE); 583 mConnectingStatusView.setText(R.string.wifi_setup_description_connecting); 584 585 mSkipOrNextButton.setVisibility(View.VISIBLE); 586 mSkipOrNextButton.setEnabled(false); 587 mConnectButton.setVisibility(View.GONE); 588 mAddNetworkButton.setVisibility(View.GONE); 589 mRefreshButton.setVisibility(View.GONE); 590 } 591 592 private void onBackButtonPressed() { 593 594 if (mScreenState == SCREEN_STATE_CONNECTING || mScreenState == SCREEN_STATE_CONNECTED) { 595 if (DEBUG) Log.d(TAG, "Back button pressed after connect action."); 596 mScreenState = SCREEN_STATE_DISCONNECTED; 597 598 // When a user press "Back" button after pressing "Connect" button, we want to cancel 599 // the "Connect" request and refresh the whole Wifi status. 600 restoreFirstVisibilityState(); 601 602 mSkipOrNextButton.setEnabled(true); 603 changeNextButtonState(false); // Skip 604 605 // Wifi list becomes empty for a moment. We show "scanning" effect to a user so that 606 // he/she won't be astonished there. This stops once the scan finishes. 607 showScanningState(); 608 609 // Remembered networks may be re-used during SetupWizard, which confuse users. 610 // We force the module to forget them to reduce UX complexity 611 final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks(); 612 for (WifiConfiguration config : configs) { 613 if (DEBUG) { 614 Log.d(TAG, String.format("forgeting Wi-Fi network \"%s\" (id: %d)", 615 config.SSID, config.networkId)); 616 } 617 mWifiManager.forgetNetwork(config.networkId); 618 } 619 620 mWifiSettingsFragmentLayout.setVisibility(View.GONE); 621 refreshAccessPoints(true); 622 } else { // During user's Wifi configuration. 623 mScreenState = SCREEN_STATE_DISCONNECTED; 624 mWifiSettings.resumeWifiScan(); 625 626 restoreFirstVisibilityState(); 627 628 mAddNetworkButton.setEnabled(true); 629 mRefreshButton.setEnabled(true); 630 mSkipOrNextButton.setEnabled(true); 631 showDisconnectedProgressBar(); 632 mWifiSettingsFragmentLayout.setVisibility(View.VISIBLE); 633 mBottomPadding.setVisibility(View.GONE); 634 } 635 636 setPaddingVisibility(View.VISIBLE); 637 mConnectingStatusLayout.setVisibility(View.GONE); 638 final ViewGroup parent = (ViewGroup)findViewById(R.id.wifi_config_ui); 639 parent.removeAllViews(); 640 parent.setVisibility(View.GONE); 641 mWifiConfig = null; 642 } 643 644 /** 645 * @param connected true when the device is connected to a specific network. 646 */ 647 /* package */ void changeNextButtonState(boolean connected) { 648 if (connected) { 649 mSkipOrNextButton.setText(R.string.wifi_setup_next); 650 } else { 651 mSkipOrNextButton.setText(R.string.wifi_setup_skip); 652 } 653 } 654 655 /** 656 * Called when the list of AccessPoints are modified and this Activity needs to refresh 657 * the list. 658 * @param preferenceScreen 659 */ 660 /* package */ void onAccessPointsUpdated( 661 PreferenceScreen preferenceScreen, Collection<AccessPoint> accessPoints) { 662 // If we already show some of access points but the bar still shows "scanning" state, it 663 // should be stopped. 664 if (mProgressBar.isIndeterminate() && accessPoints.size() > 0) { 665 showDisconnectedProgressBar(); 666 if (mScreenState == SCREEN_STATE_DISCONNECTED) { 667 mWifiSettingsFragmentLayout.setVisibility(View.VISIBLE); 668 mBottomPadding.setVisibility(View.GONE); 669 } 670 mAddNetworkButton.setEnabled(true); 671 mRefreshButton.setEnabled(true); 672 } 673 674 for (AccessPoint accessPoint : accessPoints) { 675 accessPoint.setLayoutResource(R.layout.custom_preference); 676 preferenceScreen.addPreference(accessPoint); 677 } 678 } 679 680 private void refreshAccessPoints(boolean disconnectNetwork) { 681 showScanningState(); 682 683 if (disconnectNetwork) { 684 mWifiManager.disconnect(); 685 } 686 687 mWifiSettings.refreshAccessPoints(); 688 } 689 690 /** 691 * Called when {@link WifiSettings} received 692 * {@link WifiManager#SUPPLICANT_STATE_CHANGED_ACTION}. 693 */ 694 /* package */ void onSupplicantStateChanged(Intent intent) { 695 final int errorCode = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, -1); 696 if (errorCode == WifiManager.ERROR_AUTHENTICATING) { 697 Log.i(TAG, "Received authentication error event."); 698 onAuthenticationFailure(); 699 } 700 } 701 702 /** 703 * Called once when Authentication failed. 704 */ 705 private void onAuthenticationFailure() { 706 mScreenState = SCREEN_STATE_EDITING; 707 708 mSkipOrNextButton.setVisibility(View.GONE); 709 mConnectButton.setVisibility(View.VISIBLE); 710 mConnectButton.setEnabled(true); 711 712 if (!TextUtils.isEmpty(mEditingTitle)) { 713 mTitleView.setText(mEditingTitle); 714 } else { 715 Log.w(TAG, "Title during editing/adding a network was empty."); 716 showEditingTitle(); 717 } 718 719 final ViewGroup parent = (ViewGroup)findViewById(R.id.wifi_config_ui); 720 parent.setVisibility(View.VISIBLE); 721 mConnectingStatusLayout.setVisibility(View.GONE); 722 723 showDisconnectedProgressBar(); 724 setPaddingVisibility(View.GONE); 725 } 726 727 // Used by WifiConfigUiForSetupWizardXL 728 /* package */ void setPaddingVisibility(int visibility) { 729 mTopPadding.setVisibility(visibility); 730 mContentPadding.setVisibility(visibility); 731 } 732 733 private void showDisconnectedProgressBar() { 734 // The device may report DISCONNECTED during connecting to a network, at which we don't 735 // want to lose bottom padding of top divider implicitly added by ProgressBar. 736 if (mScreenState == SCREEN_STATE_DISCONNECTED) { 737 mProgressBar.setVisibility(View.GONE); 738 mProgressBar.setIndeterminate(false); 739 mTopDividerNoProgress.setVisibility(View.VISIBLE); 740 } else { 741 mProgressBar.setVisibility(View.VISIBLE); 742 mProgressBar.setIndeterminate(false); 743 mProgressBar.setProgress(0); 744 mTopDividerNoProgress.setVisibility(View.GONE); 745 } 746 } 747 748 /** 749 * Shows top divider with ProgressBar, whose state is intermediate. 750 */ 751 private void showScanningProgressBar() { 752 showTopDividerWithProgressBar(); 753 mProgressBar.setIndeterminate(true); 754 } 755 756 /** 757 * Shows top divider with ProgressBar, showing "connecting" state. 758 */ 759 private void showConnectingProgressBar() { 760 showTopDividerWithProgressBar(); 761 mProgressBar.setIndeterminate(false); 762 mProgressBar.setProgress(1); 763 } 764 765 private void showConnectedProgressBar() { 766 showTopDividerWithProgressBar(); 767 mProgressBar.setIndeterminate(false); 768 mProgressBar.setProgress(2); 769 } 770 771 /** 772 * Called when WifiManager is requested to save a network. 773 */ 774 /* package */ void onSaveNetwork(WifiConfiguration config) { 775 // We want to both save and connect a network. connectNetwork() does both. 776 mWifiManager.connectNetwork(config); 777 } 778 } 779