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