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