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