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