WifiSettings.java revision 8a963babe2e36b7a41f77b8d2598c97658196e58
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;
20import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
21import android.app.Activity;
22import android.app.Dialog;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.content.Intent;
26import android.content.res.Resources;
27import android.content.res.TypedArray;
28import android.location.LocationManager;
29import android.net.ConnectivityManager;
30import android.net.NetworkInfo;
31import android.net.NetworkInfo.State;
32import android.net.wifi.WifiConfiguration;
33import android.net.wifi.WifiManager;
34import android.net.wifi.WpsInfo;
35import android.nfc.NfcAdapter;
36import android.os.Bundle;
37import android.preference.Preference;
38import android.preference.PreferenceScreen;
39import android.util.Log;
40import android.view.ContextMenu;
41import android.view.ContextMenu.ContextMenuInfo;
42import android.view.Menu;
43import android.view.MenuInflater;
44import android.view.MenuItem;
45import android.view.View;
46import android.widget.AdapterView.AdapterContextMenuInfo;
47import android.widget.TextView;
48import android.widget.Toast;
49
50import com.android.internal.logging.MetricsLogger;
51import com.android.settings.R;
52import com.android.settings.RestrictedSettingsFragment;
53import com.android.settings.SettingsActivity;
54import com.android.settings.search.BaseSearchIndexProvider;
55import com.android.settings.search.Indexable;
56import com.android.settings.search.SearchIndexableRaw;
57import com.android.settingslib.wifi.AccessPoint;
58import com.android.settingslib.wifi.AccessPoint.AccessPointListener;
59import com.android.settingslib.wifi.WifiTracker;
60
61import java.util.ArrayList;
62import java.util.Collection;
63import java.util.List;
64
65/**
66 * Two types of UI are provided here.
67 *
68 * The first is for "usual Settings", appearing as any other Setup fragment.
69 *
70 * The second is for Setup Wizard, with a simplified interface that hides the action bar
71 * and menus.
72 */
73public class WifiSettings extends RestrictedSettingsFragment
74        implements DialogInterface.OnClickListener, Indexable, WifiTracker.WifiListener,
75        AccessPointListener {
76
77    private static final String TAG = "WifiSettings";
78
79    /* package */ static final int MENU_ID_WPS_PBC = Menu.FIRST;
80    private static final int MENU_ID_WPS_PIN = Menu.FIRST + 1;
81    private static final int MENU_ID_SAVED_NETWORK = Menu.FIRST + 2;
82    /* package */ static final int MENU_ID_ADD_NETWORK = Menu.FIRST + 3;
83    private static final int MENU_ID_ADVANCED = Menu.FIRST + 4;
84    private static final int MENU_ID_SCAN = Menu.FIRST + 5;
85    private static final int MENU_ID_CONNECT = Menu.FIRST + 6;
86    private static final int MENU_ID_FORGET = Menu.FIRST + 7;
87    private static final int MENU_ID_MODIFY = Menu.FIRST + 8;
88    private static final int MENU_ID_WRITE_NFC = Menu.FIRST + 9;
89    private static final int MENU_ID_APPS = Menu.FIRST + 10;
90
91    public static final int WIFI_DIALOG_ID = 1;
92    /* package */ static final int WPS_PBC_DIALOG_ID = 2;
93    private static final int WPS_PIN_DIALOG_ID = 3;
94    private static final int WRITE_NFC_DIALOG_ID = 6;
95
96    // Instance state keys
97    private static final String SAVE_DIALOG_EDIT_MODE = "edit_mode";
98    private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state";
99
100    private static boolean savedNetworksExist;
101
102    protected WifiManager mWifiManager;
103    private WifiManager.ActionListener mConnectListener;
104    private WifiManager.ActionListener mSaveListener;
105    private WifiManager.ActionListener mForgetListener;
106
107    private WifiEnabler mWifiEnabler;
108    // An access point being editted is stored here.
109    private AccessPoint mSelectedAccessPoint;
110
111    private WifiDialog mDialog;
112    private WriteWifiConfigToNfcDialog mWifiToNfcDialog;
113
114    private TextView mEmptyView;
115
116    private boolean showAppIcons = false;
117    private MenuItem showAppMenuItem = null;
118
119    // this boolean extra specifies whether to disable the Next button when not connected. Used by
120    // account creation outside of setup wizard.
121    private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect";
122    // This string extra specifies a network to open the connect dialog on, so the user can enter
123    // network credentials.  This is used by quick settings for secured networks.
124    private static final String EXTRA_START_CONNECT_SSID = "wifi_start_connect_ssid";
125
126    // should Next button only be enabled when we have a connection?
127    private boolean mEnableNextOnConnection;
128
129    // Save the dialog details
130    private boolean mDlgEdit;
131    private AccessPoint mDlgAccessPoint;
132    private Bundle mAccessPointSavedState;
133
134    private WifiTracker mWifiTracker;
135
136    /* End of "used in Wifi Setup context" */
137
138    public WifiSettings() {
139        super(DISALLOW_CONFIG_WIFI);
140    }
141
142    @Override
143    public void onActivityCreated(Bundle savedInstanceState) {
144        super.onActivityCreated(savedInstanceState);
145
146        mWifiTracker = new WifiTracker(getActivity(), this, true, true);
147        mWifiManager = mWifiTracker.getManager();
148
149        mConnectListener = new WifiManager.ActionListener() {
150                                   @Override
151                                   public void onSuccess() {
152                                   }
153                                   @Override
154                                   public void onFailure(int reason) {
155                                       Activity activity = getActivity();
156                                       if (activity != null) {
157                                           Toast.makeText(activity,
158                                                R.string.wifi_failed_connect_message,
159                                                Toast.LENGTH_SHORT).show();
160                                       }
161                                   }
162                               };
163
164        mSaveListener = new WifiManager.ActionListener() {
165                                @Override
166                                public void onSuccess() {
167                                }
168                                @Override
169                                public void onFailure(int reason) {
170                                    Activity activity = getActivity();
171                                    if (activity != null) {
172                                        Toast.makeText(activity,
173                                            R.string.wifi_failed_save_message,
174                                            Toast.LENGTH_SHORT).show();
175                                    }
176                                }
177                            };
178
179        mForgetListener = new WifiManager.ActionListener() {
180                                   @Override
181                                   public void onSuccess() {
182                                   }
183                                   @Override
184                                   public void onFailure(int reason) {
185                                       Activity activity = getActivity();
186                                       if (activity != null) {
187                                           Toast.makeText(activity,
188                                               R.string.wifi_failed_forget_message,
189                                               Toast.LENGTH_SHORT).show();
190                                       }
191                                   }
192                               };
193
194        if (savedInstanceState != null) {
195            mDlgEdit = savedInstanceState.getBoolean(SAVE_DIALOG_EDIT_MODE);
196            if (savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) {
197                mAccessPointSavedState =
198                    savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE);
199            }
200        }
201
202        // if we're supposed to enable/disable the Next button based on our current connection
203        // state, start it off in the right state
204        Intent intent = getActivity().getIntent();
205        mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false);
206
207        if (mEnableNextOnConnection) {
208            if (hasNextButton()) {
209                final ConnectivityManager connectivity = (ConnectivityManager)
210                        getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
211                if (connectivity != null) {
212                    NetworkInfo info = connectivity.getNetworkInfo(
213                            ConnectivityManager.TYPE_WIFI);
214                    changeNextButtonState(info.isConnected());
215                }
216            }
217        }
218
219        addPreferencesFromResource(R.xml.wifi_settings);
220
221        mEmptyView = initEmptyView();
222        registerForContextMenu(getListView());
223        setHasOptionsMenu(true);
224
225        if (intent.hasExtra(EXTRA_START_CONNECT_SSID)) {
226            String ssid = intent.getStringExtra(EXTRA_START_CONNECT_SSID);
227            onAccessPointsChanged();
228            PreferenceScreen preferenceScreen = getPreferenceScreen();
229            for (int i = 0; i < preferenceScreen.getPreferenceCount(); i++) {
230                Preference preference = preferenceScreen.getPreference(i);
231                if (preference instanceof AccessPointPreference) {
232                    AccessPoint accessPoint = ((AccessPointPreference) preference).getAccessPoint();
233                    if (ssid.equals(accessPoint.getSsid()) && !accessPoint.isSaved()
234                            && accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
235                        onPreferenceTreeClick(preferenceScreen, preference);
236                        break;
237                    }
238                }
239            }
240        }
241    }
242
243    @Override
244    public void onDestroyView() {
245        super.onDestroyView();
246
247        if (mWifiEnabler != null) {
248            mWifiEnabler.teardownSwitchBar();
249        }
250    }
251
252    @Override
253    public void onStart() {
254        super.onStart();
255
256        // On/off switch is hidden for Setup Wizard (returns null)
257        mWifiEnabler = createWifiEnabler();
258    }
259
260    /**
261     * @return new WifiEnabler or null (as overridden by WifiSettingsForSetupWizard)
262     */
263    /* package */ WifiEnabler createWifiEnabler() {
264        final SettingsActivity activity = (SettingsActivity) getActivity();
265        return new WifiEnabler(activity, activity.getSwitchBar());
266    }
267
268    @Override
269    public void onResume() {
270        final Activity activity = getActivity();
271        super.onResume();
272        if (mWifiEnabler != null) {
273            mWifiEnabler.resume(activity);
274        }
275
276        mWifiTracker.startTracking();
277    }
278
279    @Override
280    public void onPause() {
281        super.onPause();
282        if (mWifiEnabler != null) {
283            mWifiEnabler.pause();
284        }
285
286        mWifiTracker.stopTracking();
287    }
288
289    @Override
290    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
291        // If the user is not allowed to configure wifi, do not show the menu.
292        if (isUiRestricted()) return;
293
294        addOptionsMenuItems(menu);
295        super.onCreateOptionsMenu(menu, inflater);
296    }
297
298    /**
299     * @param menu
300     */
301    void addOptionsMenuItems(Menu menu) {
302        final boolean wifiIsEnabled = mWifiTracker.isWifiEnabled();
303        TypedArray ta = getActivity().getTheme().obtainStyledAttributes(
304                new int[] {R.attr.ic_menu_add, R.attr.ic_wps});
305        menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network)
306                .setIcon(ta.getDrawable(0))
307                .setEnabled(wifiIsEnabled)
308                .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
309        if (savedNetworksExist) {
310            menu.add(Menu.NONE, MENU_ID_SAVED_NETWORK, 0, R.string.wifi_saved_access_points_label)
311                    .setIcon(ta.getDrawable(0))
312                    .setEnabled(wifiIsEnabled)
313                    .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
314        }
315        menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.menu_stats_refresh)
316               .setEnabled(wifiIsEnabled)
317               .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
318        menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)
319                .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
320        showAppMenuItem = menu.add(Menu.NONE, MENU_ID_APPS, 0, R.string.wifi_menu_apps);
321        showAppMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
322        ta.recycle();
323    }
324
325    @Override
326    protected int getMetricsCategory() {
327        return MetricsLogger.WIFI;
328    }
329
330    @Override
331    public void onSaveInstanceState(Bundle outState) {
332        super.onSaveInstanceState(outState);
333
334        // If the dialog is showing, save its state.
335        if (mDialog != null && mDialog.isShowing()) {
336            outState.putBoolean(SAVE_DIALOG_EDIT_MODE, mDlgEdit);
337            if (mDlgAccessPoint != null) {
338                mAccessPointSavedState = new Bundle();
339                mDlgAccessPoint.saveWifiState(mAccessPointSavedState);
340                outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState);
341            }
342        }
343    }
344
345    @Override
346    public boolean onOptionsItemSelected(MenuItem item) {
347        // If the user is not allowed to configure wifi, do not handle menu selections.
348        if (isUiRestricted()) return false;
349
350        switch (item.getItemId()) {
351            case MENU_ID_WPS_PBC:
352                showDialog(WPS_PBC_DIALOG_ID);
353                return true;
354                /*
355            case MENU_ID_P2P:
356                if (getActivity() instanceof SettingsActivity) {
357                    ((SettingsActivity) getActivity()).startPreferencePanel(
358                            WifiP2pSettings.class.getCanonicalName(),
359                            null,
360                            R.string.wifi_p2p_settings_title, null,
361                            this, 0);
362                } else {
363                    startFragment(this, WifiP2pSettings.class.getCanonicalName(),
364                            R.string.wifi_p2p_settings_title, -1, null);
365                }
366                return true;
367                */
368            case MENU_ID_WPS_PIN:
369                showDialog(WPS_PIN_DIALOG_ID);
370                return true;
371            case MENU_ID_SCAN:
372                mWifiTracker.forceScan();
373                return true;
374            case MENU_ID_ADD_NETWORK:
375                if (mWifiTracker.isWifiEnabled()) {
376                    onAddNetworkPressed();
377                }
378                return true;
379            case MENU_ID_SAVED_NETWORK:
380                if (getActivity() instanceof SettingsActivity) {
381                    ((SettingsActivity) getActivity()).startPreferencePanel(
382                            SavedAccessPointsWifiSettings.class.getCanonicalName(), null,
383                            R.string.wifi_saved_access_points_titlebar, null, this, 0);
384                } else {
385                    startFragment(this, SavedAccessPointsWifiSettings.class.getCanonicalName(),
386                            R.string.wifi_saved_access_points_titlebar,
387                            -1 /* Do not request a result */, null);
388                }
389                return true;
390            case MENU_ID_ADVANCED:
391                if (getActivity() instanceof SettingsActivity) {
392                    ((SettingsActivity) getActivity()).startPreferencePanel(
393                            AdvancedWifiSettings.class.getCanonicalName(), null,
394                            R.string.wifi_advanced_titlebar, null, this, 0);
395                } else {
396                    startFragment(this, AdvancedWifiSettings.class.getCanonicalName(),
397                            R.string.wifi_advanced_titlebar, -1 /* Do not request a results */,
398                            null);
399                }
400                return true;
401            case MENU_ID_APPS:
402                showAppIcons = !showAppIcons;
403
404                if (showAppIcons) {
405                    showAppMenuItem.setTitle(R.string.wifi_menu_apps_strength);
406                } else {
407                    showAppMenuItem.setTitle(R.string.wifi_menu_apps);
408                }
409                onAccessPointsChanged();
410                return true;
411        }
412        return super.onOptionsItemSelected(item);
413    }
414
415    @Override
416    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
417        if (info instanceof AdapterContextMenuInfo) {
418            Preference preference = (Preference) getListView().getItemAtPosition(
419                    ((AdapterContextMenuInfo) info).position);
420
421            if (preference instanceof AccessPointPreference) {
422                mSelectedAccessPoint = ((AccessPointPreference) preference).getAccessPoint();
423                menu.setHeaderTitle(mSelectedAccessPoint.getSsid());
424                if (mSelectedAccessPoint.isConnectable()) {
425                    menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
426                }
427
428                if (mSelectedAccessPoint.isSaved() || mSelectedAccessPoint.isEphemeral()) {
429                    // Allow forgetting a network if either the network is saved or ephemerally
430                    // connected. (In the latter case, "forget" blacklists the network so it won't
431                    // be used again, ephemerally).
432                    menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget);
433                }
434                if (mSelectedAccessPoint.isSaved()) {
435                    menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);
436                    NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
437                    if (nfcAdapter != null && nfcAdapter.isEnabled() &&
438                            mSelectedAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
439                        // Only allow writing of NFC tags for password-protected networks.
440                        menu.add(Menu.NONE, MENU_ID_WRITE_NFC, 0, R.string.wifi_menu_write_to_nfc);
441                    }
442                }
443            }
444        }
445    }
446
447    @Override
448    public boolean onContextItemSelected(MenuItem item) {
449        if (mSelectedAccessPoint == null) {
450            return super.onContextItemSelected(item);
451        }
452        switch (item.getItemId()) {
453            case MENU_ID_CONNECT: {
454                if (mSelectedAccessPoint.isSaved()) {
455                    connect(mSelectedAccessPoint.getConfig());
456                } else if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
457                    /** Bypass dialog for unsecured networks */
458                    mSelectedAccessPoint.generateOpenNetworkConfig();
459                    connect(mSelectedAccessPoint.getConfig());
460                } else {
461                    showDialog(mSelectedAccessPoint, true);
462                }
463                return true;
464            }
465            case MENU_ID_FORGET: {
466                forget();
467                return true;
468            }
469            case MENU_ID_MODIFY: {
470                showDialog(mSelectedAccessPoint, true);
471                return true;
472            }
473            case MENU_ID_WRITE_NFC:
474                showDialog(WRITE_NFC_DIALOG_ID);
475                return true;
476
477        }
478        return super.onContextItemSelected(item);
479    }
480
481    @Override
482    public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
483        if (preference instanceof AccessPointPreference) {
484            mSelectedAccessPoint = ((AccessPointPreference) preference).getAccessPoint();
485            /** Bypass dialog for unsecured, unsaved, and inactive networks */
486            if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE &&
487                    !mSelectedAccessPoint.isSaved() && !mSelectedAccessPoint.isActive()) {
488                mSelectedAccessPoint.generateOpenNetworkConfig();
489                if (!savedNetworksExist) {
490                    savedNetworksExist = true;
491                    getActivity().invalidateOptionsMenu();
492                }
493                connect(mSelectedAccessPoint.getConfig());
494            } else {
495                showDialog(mSelectedAccessPoint, false);
496            }
497        } else {
498            return super.onPreferenceTreeClick(screen, preference);
499        }
500        return true;
501    }
502
503    private void showDialog(AccessPoint accessPoint, boolean edit) {
504        if (mDialog != null) {
505            removeDialog(WIFI_DIALOG_ID);
506            mDialog = null;
507        }
508
509        // Save the access point and edit mode
510        mDlgAccessPoint = accessPoint;
511        mDlgEdit = edit;
512
513        showDialog(WIFI_DIALOG_ID);
514    }
515
516    @Override
517    public Dialog onCreateDialog(int dialogId) {
518        switch (dialogId) {
519            case WIFI_DIALOG_ID:
520                AccessPoint ap = mDlgAccessPoint; // For manual launch
521                if (ap == null) { // For re-launch from saved state
522                    if (mAccessPointSavedState != null) {
523                        ap = new AccessPoint(getActivity(), mAccessPointSavedState);
524                        // For repeated orientation changes
525                        mDlgAccessPoint = ap;
526                        // Reset the saved access point data
527                        mAccessPointSavedState = null;
528                    }
529                }
530                // If it's null, fine, it's for Add Network
531                mSelectedAccessPoint = ap;
532                mDialog = new WifiDialog(getActivity(), this, ap, mDlgEdit);
533                return mDialog;
534            case WPS_PBC_DIALOG_ID:
535                return new WpsDialog(getActivity(), WpsInfo.PBC);
536            case WPS_PIN_DIALOG_ID:
537                return new WpsDialog(getActivity(), WpsInfo.DISPLAY);
538            case WRITE_NFC_DIALOG_ID:
539                if (mSelectedAccessPoint != null) {
540                    mWifiToNfcDialog = new WriteWifiConfigToNfcDialog(
541                            getActivity(), mSelectedAccessPoint, mWifiManager);
542                    return mWifiToNfcDialog;
543                }
544
545        }
546        return super.onCreateDialog(dialogId);
547    }
548
549    /**
550     * Shows the latest access points available with supplemental information like
551     * the strength of network and the security for it.
552     */
553    @Override
554    public void onAccessPointsChanged() {
555        // Safeguard from some delayed event handling
556        if (getActivity() == null) return;
557
558        if (isUiRestricted()) {
559            addMessagePreference(R.string.wifi_empty_list_user_restricted);
560            return;
561        }
562        final int wifiState = mWifiManager.getWifiState();
563
564        switch (wifiState) {
565            case WifiManager.WIFI_STATE_ENABLED:
566                // AccessPoints are automatically sorted with TreeSet.
567                final Collection<AccessPoint> accessPoints =
568                        mWifiTracker.getAccessPoints();
569                getPreferenceScreen().removeAll();
570                if (accessPoints.size() == 0) {
571                    addMessagePreference(R.string.wifi_empty_list_wifi_on);
572                }
573
574                for (AccessPoint accessPoint : accessPoints) {
575                    // Ignore access points that are out of range.
576                    if (accessPoint.getLevel() != -1) {
577                        AccessPointPreference preference = new AccessPointPreference(accessPoint,
578                                getActivity());
579                        if (showAppIcons) {
580                            preference.showAppIcon();
581                        }
582
583                        getPreferenceScreen().addPreference(preference);
584                        accessPoint.setListener(this);
585                    }
586                }
587                break;
588
589            case WifiManager.WIFI_STATE_ENABLING:
590                getPreferenceScreen().removeAll();
591                break;
592
593            case WifiManager.WIFI_STATE_DISABLING:
594                addMessagePreference(R.string.wifi_stopping);
595                break;
596
597            case WifiManager.WIFI_STATE_DISABLED:
598                setOffMessage();
599                break;
600        }
601        // Update "Saved Networks" menu option.
602        if (savedNetworksExist != mWifiTracker.doSavedNetworksExist()) {
603            savedNetworksExist = !savedNetworksExist;
604            getActivity().invalidateOptionsMenu();
605        }
606    }
607
608    protected TextView initEmptyView() {
609        TextView emptyView = (TextView) getActivity().findViewById(android.R.id.empty);
610        getListView().setEmptyView(emptyView);
611        return emptyView;
612    }
613
614    private void setOffMessage() {
615        if (mEmptyView != null) {
616            mEmptyView.setText(R.string.wifi_empty_list_wifi_off);
617            if (android.provider.Settings.Global.getInt(getActivity().getContentResolver(),
618                    android.provider.Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1) {
619                mEmptyView.append("\n\n");
620                int resId;
621                if (android.provider.Settings.Secure.isLocationProviderEnabled(
622                        getActivity().getContentResolver(), LocationManager.NETWORK_PROVIDER)) {
623                    resId = R.string.wifi_scan_notify_text_location_on;
624                } else {
625                    resId = R.string.wifi_scan_notify_text_location_off;
626                }
627                CharSequence charSeq = getText(resId);
628                mEmptyView.append(charSeq);
629            }
630        }
631        getPreferenceScreen().removeAll();
632    }
633
634    private void addMessagePreference(int messageId) {
635        if (mEmptyView != null) mEmptyView.setText(messageId);
636        getPreferenceScreen().removeAll();
637    }
638
639    @Override
640    public void onWifiStateChanged(int state) {
641        Activity activity = getActivity();
642        if (activity != null) {
643            activity.invalidateOptionsMenu();
644        }
645
646        switch (state) {
647            case WifiManager.WIFI_STATE_ENABLING:
648                addMessagePreference(R.string.wifi_starting);
649                break;
650
651            case WifiManager.WIFI_STATE_DISABLED:
652                setOffMessage();
653                break;
654        }
655    }
656
657    @Override
658    public void onConnectedChanged() {
659        changeNextButtonState(mWifiTracker.isConnected());
660    }
661
662    /**
663     * Renames/replaces "Next" button when appropriate. "Next" button usually exists in
664     * Wifi setup screens, not in usual wifi settings screen.
665     *
666     * @param enabled true when the device is connected to a wifi network.
667     */
668    private void changeNextButtonState(boolean enabled) {
669        if (mEnableNextOnConnection && hasNextButton()) {
670            getNextButton().setEnabled(enabled);
671        }
672    }
673
674    @Override
675    public void onClick(DialogInterface dialogInterface, int button) {
676        if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
677            forget();
678        } else if (button == WifiDialog.BUTTON_SUBMIT) {
679            if (mDialog != null) {
680                submit(mDialog.getController());
681            }
682        }
683    }
684
685    /* package */ void submit(WifiConfigController configController) {
686
687        final WifiConfiguration config = configController.getConfig();
688
689        if (config == null) {
690            if (mSelectedAccessPoint != null
691                    && mSelectedAccessPoint.isSaved()) {
692                connect(mSelectedAccessPoint.getConfig());
693            }
694        } else if (config.networkId != INVALID_NETWORK_ID) {
695            if (mSelectedAccessPoint != null) {
696                mWifiManager.save(config, mSaveListener);
697            }
698        } else {
699            if (configController.isEdit()) {
700                mWifiManager.save(config, mSaveListener);
701            } else {
702                connect(config);
703            }
704        }
705
706        mWifiTracker.resumeScanning();
707    }
708
709    /* package */ void forget() {
710        if (!mSelectedAccessPoint.isSaved()) {
711            if (mSelectedAccessPoint.getNetworkInfo().getState() != State.DISCONNECTED) {
712                // Network is active but has no network ID - must be ephemeral.
713                mWifiManager.disableEphemeralNetwork(
714                        AccessPoint.convertToQuotedString(mSelectedAccessPoint.getSsid()));
715            } else {
716                // Should not happen, but a monkey seems to trigger it
717                Log.e(TAG, "Failed to forget invalid network " + mSelectedAccessPoint.getConfig());
718                return;
719            }
720        } else {
721            mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId, mForgetListener);
722        }
723
724        mWifiTracker.resumeScanning();
725
726        // We need to rename/replace "Next" button in wifi setup context.
727        changeNextButtonState(false);
728    }
729
730    protected void connect(final WifiConfiguration config) {
731        mWifiManager.connect(config, mConnectListener);
732    }
733
734    protected void connect(final int networkId) {
735        mWifiManager.connect(networkId, mConnectListener);
736    }
737
738    /**
739     * Refreshes acccess points and ask Wifi module to scan networks again.
740     */
741    /* package */ void refreshAccessPoints() {
742        mWifiTracker.resumeScanning();
743
744        getPreferenceScreen().removeAll();
745    }
746
747    /**
748     * Called when "add network" button is pressed.
749     */
750    /* package */ void onAddNetworkPressed() {
751        // No exact access point is selected.
752        mSelectedAccessPoint = null;
753        showDialog(null, true);
754    }
755
756    /* package */ int getAccessPointsCount() {
757        final boolean wifiIsEnabled = mWifiTracker.isWifiEnabled();
758        if (wifiIsEnabled) {
759            return getPreferenceScreen().getPreferenceCount();
760        } else {
761            return 0;
762        }
763    }
764
765    /**
766     * Requests wifi module to pause wifi scan. May be ignored when the module is disabled.
767     */
768    /* package */ void pauseWifiScan() {
769        mWifiTracker.pauseScanning();
770    }
771
772    /**
773     * Requests wifi module to resume wifi scan. May be ignored when the module is disabled.
774     */
775    /* package */ void resumeWifiScan() {
776        mWifiTracker.resumeScanning();
777    }
778
779    @Override
780    protected int getHelpResource() {
781        return R.string.help_url_wifi;
782    }
783
784    @Override
785    public void onAccessPointChanged(AccessPoint accessPoint) {
786        ((AccessPointPreference) accessPoint.getTag()).refresh();
787    }
788
789    @Override
790    public void onLevelChanged(AccessPoint accessPoint) {
791        ((AccessPointPreference) accessPoint.getTag()).onLevelChanged();
792    }
793
794    public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
795        new BaseSearchIndexProvider() {
796            @Override
797            public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
798                final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
799                final Resources res = context.getResources();
800
801                // Add fragment title
802                SearchIndexableRaw data = new SearchIndexableRaw(context);
803                data.title = res.getString(R.string.wifi_settings);
804                data.screenTitle = res.getString(R.string.wifi_settings);
805                data.keywords = res.getString(R.string.keywords_wifi);
806                result.add(data);
807
808                // Add saved Wi-Fi access points
809                final Collection<AccessPoint> accessPoints =
810                        WifiTracker.getCurrentAccessPoints(context, true, false);
811                for (AccessPoint accessPoint : accessPoints) {
812                    data = new SearchIndexableRaw(context);
813                    data.title = accessPoint.getSsid();
814                    data.screenTitle = res.getString(R.string.wifi_settings);
815                    data.enabled = enabled;
816                    result.add(data);
817                }
818
819                return result;
820            }
821        };
822}
823