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