WifiSettings.java revision 7bdf0e73d051f176fbc20451761eb50177d69f91
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings.wifi;
18
19import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
20
21import com.android.settings.ProgressCategoryBase;
22import com.android.settings.R;
23import com.android.settings.SettingsPreferenceFragment;
24
25import android.app.Activity;
26import android.app.AlertDialog;
27import android.content.BroadcastReceiver;
28import android.content.Context;
29import android.content.DialogInterface;
30import android.content.Intent;
31import android.content.IntentFilter;
32import android.net.ConnectivityManager;
33import android.net.NetworkInfo;
34import android.net.NetworkInfo.DetailedState;
35import android.net.wifi.ScanResult;
36import android.net.wifi.SupplicantState;
37import android.net.wifi.WifiConfiguration;
38import android.net.wifi.WifiInfo;
39import android.net.wifi.WifiManager;
40import android.net.wifi.WpsResult;
41import android.net.wifi.WifiConfiguration.KeyMgmt;
42import android.net.wifi.WpsConfiguration;
43import android.os.Bundle;
44import android.os.Handler;
45import android.os.Message;
46import android.preference.CheckBoxPreference;
47import android.preference.Preference;
48import android.preference.ListPreference;
49import android.preference.PreferenceActivity;
50import android.preference.PreferenceScreen;
51import android.provider.Settings.Secure;
52import android.provider.Settings;
53import android.security.Credentials;
54import android.security.KeyStore;
55import android.view.ContextMenu;
56import android.view.LayoutInflater;
57import android.view.Menu;
58import android.view.MenuInflater;
59import android.view.MenuItem;
60import android.view.View;
61import android.view.ViewGroup;
62import android.view.ContextMenu.ContextMenuInfo;
63import android.widget.Toast;
64import android.widget.AdapterView.AdapterContextMenuInfo;
65
66import java.util.ArrayList;
67import java.util.Collection;
68import java.util.List;
69import java.util.concurrent.atomic.AtomicBoolean;
70
71/**
72 * This currently provides three types of UI.
73 *
74 * Two are for phones with relatively small screens: "for SetupWizard" and "for usual Settings".
75 * Users just need to launch WifiSettings Activity as usual. The request will be appropriately
76 * handled by ActivityManager, and they will have appropriate look-and-feel with this fragment.
77 *
78 * Third type is for Setup Wizard with X-Large, landscape UI. Users need to launch
79 * {@link WifiSettingsForSetupWizardXL} Activity, which contains this fragment but also has
80 * other decorations specific to that screen.
81 */
82public class WifiSettings extends SettingsPreferenceFragment
83        implements DialogInterface.OnClickListener, Preference.OnPreferenceChangeListener  {
84    private static final int MENU_ID_SCAN = Menu.FIRST;
85    private static final int MENU_ID_ADVANCED = Menu.FIRST + 1;
86    private static final int MENU_ID_CONNECT = Menu.FIRST + 2;
87    private static final int MENU_ID_FORGET = Menu.FIRST + 3;
88    private static final int MENU_ID_MODIFY = Menu.FIRST + 4;
89    private static final String KEY_SLEEP_POLICY = "sleep_policy";
90
91    private final IntentFilter mFilter;
92    private final BroadcastReceiver mReceiver;
93    private final Scanner mScanner;
94
95    private WifiManager mWifiManager;
96    private WifiEnabler mWifiEnabler;
97    private CheckBoxPreference mNotifyOpenNetworks;
98    private ProgressCategoryBase mAccessPoints;
99    private Preference mAddNetwork;
100    // An access point being editted is stored here.
101    private AccessPoint mSelectedAccessPoint;
102    private boolean mEdit;
103
104    private DetailedState mLastState;
105    private WifiInfo mLastInfo;
106
107    private AtomicBoolean mConnected = new AtomicBoolean(false);
108
109    private int mKeyStoreNetworkId = INVALID_NETWORK_ID;
110
111    private WifiDialog mDialog;
112
113    /* Used in Wifi Setup context */
114
115    // this boolean extra specifies whether to disable the Next button when not connected
116    private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect";
117
118    // should Next button only be enabled when we have a connection?
119    private boolean mEnableNextOnConnection;
120    private boolean mInXlSetupWizard;
121
122    /* End of "used in Wifi Setup context" */
123
124    public WifiSettings() {
125        mFilter = new IntentFilter();
126        mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
127        mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
128        mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
129        mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
130        mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
131        mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
132        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
133        mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
134        mFilter.addAction(WifiManager.ERROR_ACTION);
135
136        mReceiver = new BroadcastReceiver() {
137            @Override
138            public void onReceive(Context context, Intent intent) {
139                handleEvent(context, intent);
140            }
141        };
142
143        mScanner = new Scanner();
144    }
145
146    @Override
147    public void onAttach(Activity activity) {
148        super.onAttach(activity);
149
150        mInXlSetupWizard = (activity instanceof WifiSettingsForSetupWizardXL);
151    }
152
153    @Override
154    public View onCreateView(LayoutInflater inflater, ViewGroup container,
155            Bundle savedInstanceState) {
156        if (mInXlSetupWizard) {
157            return inflater.inflate(R.layout.custom_preference_list_fragment, container, false);
158        } else {
159            return super.onCreateView(inflater, container, savedInstanceState);
160        }
161    }
162
163    @Override
164    public void onActivityCreated(Bundle savedInstanceState) {
165        // We don't call super.onActivityCreated() here, since it assumes we already set up
166        // Preference (probably in onCreate()), while WifiSettings exceptionally set it up in
167        // this method.
168
169        mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
170
171        final Activity activity = getActivity();
172        final Intent intent = activity.getIntent();
173
174        // if we're supposed to enable/disable the Next button based on our current connection
175        // state, start it off in the right state
176        mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false);
177
178        // Avoid re-adding on returning from an overlapping activity/fragment.
179        if (getPreferenceScreen() == null || getPreferenceScreen().getPreferenceCount() < 2) {
180            if (mEnableNextOnConnection) {
181                if (hasNextButton()) {
182                    final ConnectivityManager connectivity = (ConnectivityManager)
183                            getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
184                    if (connectivity != null) {
185                        NetworkInfo info = connectivity.getNetworkInfo(
186                                ConnectivityManager.TYPE_WIFI);
187                        changeNextButtonState(info.isConnected());
188                    }
189                }
190            }
191
192            if (mInXlSetupWizard) {
193                addPreferencesFromResource(R.xml.wifi_access_points_for_wifi_setup_xl);
194            } else if (intent.getBooleanExtra("only_access_points", false)) {
195                addPreferencesFromResource(R.xml.wifi_access_points);
196            } else {
197                addPreferencesFromResource(R.xml.wifi_settings);
198                mWifiEnabler = new WifiEnabler(activity,
199                        (CheckBoxPreference) findPreference("enable_wifi"));
200                mNotifyOpenNetworks =
201                        (CheckBoxPreference) findPreference("notify_open_networks");
202                mNotifyOpenNetworks.setChecked(Secure.getInt(getContentResolver(),
203                        Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
204            }
205            // This may be either ProgressCategory or AccessPointCategoryForXL.
206            final ProgressCategoryBase preference =
207                    (ProgressCategoryBase) findPreference("access_points");
208            mAccessPoints = preference;
209            mAccessPoints.setOrderingAsAdded(false);
210            mAddNetwork = findPreference("add_network");
211
212            ListPreference pref = (ListPreference) findPreference(KEY_SLEEP_POLICY);
213            pref.setOnPreferenceChangeListener(this);
214            int value = Settings.System.getInt(getContentResolver(),
215                    Settings.System.WIFI_SLEEP_POLICY,
216                    Settings.System.WIFI_SLEEP_POLICY_NEVER);
217            pref.setValue(String.valueOf(value));
218
219            registerForContextMenu(getListView());
220            setHasOptionsMenu(true);
221        }
222
223        // After confirming PreferenceScreen is available, we call super.
224        super.onActivityCreated(savedInstanceState);
225
226    }
227
228    @Override
229    public void onResume() {
230        super.onResume();
231        if (mWifiEnabler != null) {
232            mWifiEnabler.resume();
233        }
234        getActivity().registerReceiver(mReceiver, mFilter);
235        if (mKeyStoreNetworkId != INVALID_NETWORK_ID &&
236                KeyStore.getInstance().test() == KeyStore.NO_ERROR) {
237            mWifiManager.connectNetwork(mKeyStoreNetworkId);
238        }
239        mKeyStoreNetworkId = INVALID_NETWORK_ID;
240        updateAccessPoints();
241    }
242
243    @Override
244    public void onPause() {
245        super.onPause();
246        if (mWifiEnabler != null) {
247            mWifiEnabler.pause();
248        }
249        getActivity().unregisterReceiver(mReceiver);
250        mScanner.pause();
251        if (mDialog != null) {
252            mDialog.dismiss();
253            mDialog = null;
254        }
255    }
256
257    @Override
258    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
259        // We don't want menus in Setup Wizard XL.
260        if (!mInXlSetupWizard) {
261            menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan)
262                    .setIcon(R.drawable.ic_menu_scan_network);
263            menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)
264                    .setIcon(android.R.drawable.ic_menu_manage);
265        }
266        super.onCreateOptionsMenu(menu, inflater);
267    }
268
269    @Override
270    public boolean onOptionsItemSelected(MenuItem item) {
271        switch (item.getItemId()) {
272            case MENU_ID_SCAN:
273                if (mWifiManager.isWifiEnabled()) {
274                    mScanner.forceScan();
275                }
276                return true;
277            case MENU_ID_ADVANCED:
278                if (getActivity() instanceof PreferenceActivity) {
279                    ((PreferenceActivity) getActivity()).startPreferencePanel(
280                            AdvancedSettings.class.getCanonicalName(),
281                            null,
282                            R.string.wifi_advanced_titlebar, null,
283                            this, 0);
284                } else {
285                    startFragment(this, AdvancedSettings.class.getCanonicalName(), -1, null);
286                }
287                return true;
288        }
289        return super.onOptionsItemSelected(item);
290    }
291
292    @Override
293    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
294        if (mInXlSetupWizard) {
295            ((WifiSettingsForSetupWizardXL)getActivity()).onCreateContextMenu(menu, view, info);
296        } else if (info instanceof AdapterContextMenuInfo) {
297            Preference preference = (Preference) getListView().getItemAtPosition(
298                    ((AdapterContextMenuInfo) info).position);
299
300            if (preference instanceof AccessPoint) {
301                mSelectedAccessPoint = (AccessPoint) preference;
302                menu.setHeaderTitle(mSelectedAccessPoint.ssid);
303                if (mSelectedAccessPoint.getLevel() != -1
304                        && mSelectedAccessPoint.getState() == null) {
305                    menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
306                }
307                if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
308                    menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget);
309                    menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);
310                }
311            }
312        }
313    }
314
315    @Override
316    public boolean onContextItemSelected(MenuItem item) {
317        if (mSelectedAccessPoint == null) {
318            return super.onContextItemSelected(item);
319        }
320        switch (item.getItemId()) {
321            case MENU_ID_CONNECT: {
322                if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
323                    if (!requireKeyStore(mSelectedAccessPoint.getConfig())) {
324                        mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);
325                    }
326                } else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {
327                    // Shortcut for open networks.
328                    WifiConfiguration config = new WifiConfiguration();
329                    config.SSID = AccessPoint.convertToQuotedString(mSelectedAccessPoint.ssid);
330                    config.allowedKeyManagement.set(KeyMgmt.NONE);
331                    mWifiManager.connectNetwork(config);
332                } else {
333                    showConfigUi(mSelectedAccessPoint, true);
334                }
335                return true;
336            }
337            case MENU_ID_FORGET: {
338                mWifiManager.forgetNetwork(mSelectedAccessPoint.networkId);
339                return true;
340            }
341            case MENU_ID_MODIFY: {
342                showConfigUi(mSelectedAccessPoint, true);
343                return true;
344            }
345        }
346        return super.onContextItemSelected(item);
347    }
348
349    @Override
350    public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
351        if (preference instanceof AccessPoint) {
352            mSelectedAccessPoint = (AccessPoint) preference;
353            showConfigUi(mSelectedAccessPoint, false);
354        } else if (preference == mAddNetwork) {
355            onAddNetworkPressed();
356        } else if (preference == mNotifyOpenNetworks) {
357            Secure.putInt(getContentResolver(),
358                    Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
359                    mNotifyOpenNetworks.isChecked() ? 1 : 0);
360        } else {
361            return super.onPreferenceTreeClick(screen, preference);
362        }
363        return true;
364    }
365
366    public boolean onPreferenceChange(Preference preference, Object newValue) {
367        String key = preference.getKey();
368        if (key == null) return true;
369
370        if (key.equals(KEY_SLEEP_POLICY)) {
371            try {
372                Settings.System.putInt(getContentResolver(),
373                        Settings.System.WIFI_SLEEP_POLICY, Integer.parseInt(((String) newValue)));
374            } catch (NumberFormatException e) {
375                Toast.makeText(getActivity(), R.string.wifi_setting_sleep_policy_error,
376                        Toast.LENGTH_SHORT).show();
377                return false;
378            }
379        }
380
381        return true;
382    }
383
384
385    /**
386     * Shows an appropriate Wifi configuration component.
387     * Called when a user clicks "Add network" preference or one of available networks is selected.
388     */
389    private void showConfigUi(AccessPoint accessPoint, boolean edit) {
390        mEdit = edit;
391        if (mInXlSetupWizard) {
392            ((WifiSettingsForSetupWizardXL)getActivity()).showConfigUi(accessPoint, edit);
393        } else {
394            showDialog(accessPoint, edit);
395        }
396    }
397
398    private void showDialog(AccessPoint accessPoint, boolean edit) {
399        if (mDialog != null) {
400            mDialog.dismiss();
401        }
402        mDialog = new WifiDialog(getActivity(), this, accessPoint, edit);
403        mDialog.show();
404    }
405
406    private boolean requireKeyStore(WifiConfiguration config) {
407        if (WifiConfigController.requireKeyStore(config) &&
408                KeyStore.getInstance().test() != KeyStore.NO_ERROR) {
409            mKeyStoreNetworkId = config.networkId;
410            Credentials.getInstance().unlock(getActivity());
411            return true;
412        }
413        return false;
414    }
415
416    /**
417     * Shows the latest access points available with supplimental information like
418     * the strength of network and the security for it.
419     */
420    private void updateAccessPoints() {
421        mAccessPoints.removeAll();
422
423        // AccessPoints are automatically sorted with TreeSet.
424        final Collection<AccessPoint> accessPoints = constructAccessPoints();
425        if (mInXlSetupWizard) {
426            ((WifiSettingsForSetupWizardXL)getActivity()).onAccessPointsUpdated(
427                    mAccessPoints, accessPoints);
428        } else {
429            for (AccessPoint accessPoint : accessPoints) {
430                mAccessPoints.addPreference(accessPoint);
431            }
432        }
433    }
434
435    private Collection<AccessPoint> constructAccessPoints() {
436        Collection<AccessPoint> accessPoints = new ArrayList<AccessPoint>();
437
438        final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
439        if (configs != null) {
440            for (WifiConfiguration config : configs) {
441                AccessPoint accessPoint = new AccessPoint(getActivity(), config);
442                accessPoint.update(mLastInfo, mLastState);
443                accessPoints.add(accessPoint);
444            }
445        }
446
447        final List<ScanResult> results = mWifiManager.getScanResults();
448        if (results != null) {
449            for (ScanResult result : results) {
450                // Ignore hidden and ad-hoc networks.
451                if (result.SSID == null || result.SSID.length() == 0 ||
452                        result.capabilities.contains("[IBSS]")) {
453                    continue;
454                }
455
456                boolean found = false;
457                for (AccessPoint accessPoint : accessPoints) {
458                    if (accessPoint.update(result)) {
459                        found = true;
460                    }
461                }
462                if (!found) {
463                    accessPoints.add(new AccessPoint(getActivity(), result));
464                }
465            }
466        }
467
468        return accessPoints;
469    }
470
471    private void handleEvent(Context context, Intent intent) {
472        String action = intent.getAction();
473        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
474            updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
475                    WifiManager.WIFI_STATE_UNKNOWN));
476        } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) ||
477                WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) ||
478                WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
479                updateAccessPoints();
480        } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
481            //Ignore supplicant state changes when network is connected
482            //TODO: we should deprecate SUPPLICANT_STATE_CHANGED_ACTION and
483            //introduce a broadcast that combines the supplicant and network
484            //network state change events so the apps dont have to worry about
485            //ignoring supplicant state change when network is connected
486            //to get more fine grained information.
487            if (!mConnected.get()) {
488                updateConnectionState(WifiInfo.getDetailedStateOf((SupplicantState)
489                        intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
490            }
491
492            if (mInXlSetupWizard) {
493                ((WifiSettingsForSetupWizardXL)getActivity()).onSupplicantStateChanged(intent);
494            }
495        } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
496            NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
497                    WifiManager.EXTRA_NETWORK_INFO);
498            mConnected.set(info.isConnected());
499            changeNextButtonState(info.isConnected());
500            updateConnectionState(info.getDetailedState());
501        } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
502            updateConnectionState(null);
503        } else if (WifiManager.ERROR_ACTION.equals(action)) {
504            int errorCode = intent.getIntExtra(WifiManager.EXTRA_ERROR_CODE, 0);
505            switch (errorCode) {
506                case WifiManager.WPS_OVERLAP_ERROR:
507                    Toast.makeText(context, R.string.wifi_wps_overlap_error,
508                            Toast.LENGTH_SHORT).show();
509                    break;
510            }
511        }
512    }
513
514    private void updateConnectionState(DetailedState state) {
515        /* sticky broadcasts can call this when wifi is disabled */
516        if (!mWifiManager.isWifiEnabled()) {
517            mScanner.pause();
518            return;
519        }
520
521        if (state == DetailedState.OBTAINING_IPADDR) {
522            mScanner.pause();
523        } else {
524            mScanner.resume();
525        }
526
527        mLastInfo = mWifiManager.getConnectionInfo();
528        if (state != null) {
529            mLastState = state;
530        }
531
532        for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) {
533            // Maybe there's a WifiConfigPreference
534            Preference preference = mAccessPoints.getPreference(i);
535            if (preference instanceof AccessPoint) {
536                final AccessPoint accessPoint = (AccessPoint) preference;
537                accessPoint.update(mLastInfo, mLastState);
538            }
539        }
540
541        if (mInXlSetupWizard) {
542            ((WifiSettingsForSetupWizardXL)getActivity()).updateConnectionState(mLastState);
543        }
544    }
545
546    private void updateWifiState(int state) {
547        if (state == WifiManager.WIFI_STATE_ENABLED) {
548            mScanner.resume();
549        } else {
550            mScanner.pause();
551            mAccessPoints.removeAll();
552        }
553    }
554
555    private class Scanner extends Handler {
556        private int mRetry = 0;
557
558        void resume() {
559            if (!hasMessages(0)) {
560                sendEmptyMessage(0);
561            }
562        }
563
564        void forceScan() {
565            sendEmptyMessage(0);
566        }
567
568        void pause() {
569            mRetry = 0;
570            mAccessPoints.setProgress(false);
571            removeMessages(0);
572        }
573
574        @Override
575        public void handleMessage(Message message) {
576            if (mWifiManager.startScanActive()) {
577                mRetry = 0;
578            } else if (++mRetry >= 3) {
579                mRetry = 0;
580                Toast.makeText(getActivity(), R.string.wifi_fail_to_scan,
581                        Toast.LENGTH_LONG).show();
582                return;
583            }
584            mAccessPoints.setProgress(mRetry != 0);
585            // Combo scans can take 5-6s to complete. Increase interval to 10s.
586            sendEmptyMessageDelayed(0, 10000);
587        }
588    }
589
590    /**
591     * Renames/replaces "Next" button when appropriate. "Next" button usually exists in
592     * Wifi setup screens, not in usual wifi settings screen.
593     *
594     * @param connected true when the device is connected to a wifi network.
595     */
596    private void changeNextButtonState(boolean connected) {
597        if (mInXlSetupWizard) {
598            ((WifiSettingsForSetupWizardXL)getActivity()).changeNextButtonState(connected);
599        } else if (mEnableNextOnConnection && hasNextButton()) {
600            getNextButton().setEnabled(connected);
601        }
602    }
603
604    public void onClick(DialogInterface dialogInterface, int button) {
605        if (mInXlSetupWizard) {
606            if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
607                forget();
608            } else if (button == WifiDialog.BUTTON_SUBMIT) {
609                ((WifiSettingsForSetupWizardXL)getActivity()).onConnectButtonPressed();
610            }
611        } else {
612            if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
613                forget();
614            } else if (button == WifiDialog.BUTTON_SUBMIT) {
615                submit(mDialog.getController());
616            }
617        }
618
619    }
620
621    /* package */ void submit(WifiConfigController configController) {
622        int networkSetup = configController.chosenNetworkSetupMethod();
623        switch(networkSetup) {
624            case WifiConfigController.WPS_PBC:
625            case WifiConfigController.WPS_PIN_FROM_ACCESS_POINT:
626            case WifiConfigController.WPS_PIN_FROM_DEVICE:
627                WpsResult result = mWifiManager.startWps(configController.getWpsConfig());
628                AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity())
629                                        .setTitle(R.string.wifi_wps_setup_title)
630                                        .setPositiveButton(android.R.string.ok, null);
631                switch (result.status) {
632                    case FAILURE:
633                        dialog.setMessage(R.string.wifi_wps_failed);
634                        dialog.show();
635                        break;
636                    case IN_PROGRESS:
637                        dialog.setMessage(R.string.wifi_wps_in_progress);
638                        dialog.show();
639                        break;
640                    default:
641                        if (networkSetup == WifiConfigController.WPS_PIN_FROM_DEVICE) {
642                            dialog.setMessage(getResources().getString(R.string.wifi_wps_pin_output,
643                                    result.pin));
644                            dialog.show();
645                        }
646                        break;
647                }
648                break;
649            case WifiConfigController.MANUAL:
650                final WifiConfiguration config = configController.getConfig();
651
652                if (config == null) {
653                    if (mSelectedAccessPoint != null
654                            && !requireKeyStore(mSelectedAccessPoint.getConfig())
655                            && mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
656                        mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);
657                    }
658                } else if (config.networkId != INVALID_NETWORK_ID) {
659                    if (mSelectedAccessPoint != null) {
660                        saveNetwork(config);
661                    }
662                } else {
663                    if (configController.isEdit() || requireKeyStore(config)) {
664                        saveNetwork(config);
665                    } else {
666                        mWifiManager.connectNetwork(config);
667                    }
668                }
669                break;
670        }
671
672        if (mWifiManager.isWifiEnabled()) {
673            mScanner.resume();
674        }
675        updateAccessPoints();
676    }
677
678    private void saveNetwork(WifiConfiguration config) {
679        if (mInXlSetupWizard) {
680            ((WifiSettingsForSetupWizardXL)getActivity()).onSaveNetwork(config);
681        } else {
682            mWifiManager.saveNetwork(config);
683        }
684    }
685
686    /* package */ void forget() {
687        mWifiManager.forgetNetwork(mSelectedAccessPoint.networkId);
688
689        if (mWifiManager.isWifiEnabled()) {
690            mScanner.resume();
691        }
692        updateAccessPoints();
693
694        // We need to rename/replace "Next" button in wifi setup context.
695        changeNextButtonState(false);
696    }
697
698    /**
699     * Refreshes acccess points and ask Wifi module to scan networks again.
700     */
701    /* package */ void refreshAccessPoints() {
702        if (mWifiManager.isWifiEnabled()) {
703            mScanner.resume();
704        }
705
706        mAccessPoints.removeAll();
707    }
708
709    /**
710     * Called when "add network" button is pressed.
711     */
712    /* package */ void onAddNetworkPressed() {
713        // No exact access point is selected.
714        mSelectedAccessPoint = null;
715        showConfigUi(null, true);
716    }
717
718    /* package */ int getAccessPointsCount() {
719        if (mAccessPoints != null) {
720            return mAccessPoints.getPreferenceCount();
721        } else {
722            return 0;
723        }
724    }
725
726    /**
727     * Requests wifi module to pause wifi scan. May be ignored when the module is disabled.
728     */
729    /* package */ void pauseWifiScan() {
730        if (mWifiManager.isWifiEnabled()) {
731            mScanner.pause();
732        }
733    }
734
735    /**
736     * Requests wifi module to resume wifi scan. May be ignored when the module is disabled.
737     */
738    /* package */ void resumeWifiScan() {
739        if (mWifiManager.isWifiEnabled()) {
740            mScanner.resume();
741        }
742    }
743}
744