• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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