Home | History | Annotate | Download | only in wifi
      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 
     17 package com.android.settings.wifi;
     18 
     19 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
     20 import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
     21 
     22 import android.annotation.NonNull;
     23 import android.app.Activity;
     24 import android.app.Dialog;
     25 import android.content.ContentResolver;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.content.res.Resources;
     29 import android.net.ConnectivityManager;
     30 import android.net.Network;
     31 import android.net.NetworkInfo;
     32 import android.net.NetworkInfo.State;
     33 import android.net.NetworkRequest;
     34 import android.net.wifi.WifiConfiguration;
     35 import android.net.wifi.WifiManager;
     36 import android.nfc.NfcAdapter;
     37 import android.os.Bundle;
     38 import android.os.Handler;
     39 import android.os.Looper;
     40 import android.os.PowerManager;
     41 import android.provider.Settings;
     42 import android.support.annotation.VisibleForTesting;
     43 import android.support.v7.preference.Preference;
     44 import android.support.v7.preference.PreferenceCategory;
     45 import android.util.Log;
     46 import android.view.ContextMenu;
     47 import android.view.ContextMenu.ContextMenuInfo;
     48 import android.view.Menu;
     49 import android.view.MenuItem;
     50 import android.view.View;
     51 import android.widget.Toast;
     52 
     53 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     54 import com.android.settings.LinkifyUtils;
     55 import com.android.settings.R;
     56 import com.android.settings.RestrictedSettingsFragment;
     57 import com.android.settings.SettingsActivity;
     58 import com.android.settings.core.SubSettingLauncher;
     59 import com.android.settings.dashboard.SummaryLoader;
     60 import com.android.settings.location.ScanningSettings;
     61 import com.android.settings.search.BaseSearchIndexProvider;
     62 import com.android.settings.search.Indexable;
     63 import com.android.settings.search.SearchIndexableRaw;
     64 import com.android.settings.widget.SummaryUpdater.OnSummaryChangeListener;
     65 import com.android.settings.widget.SwitchBarController;
     66 import com.android.settings.wifi.details.WifiNetworkDetailsFragment;
     67 import com.android.settingslib.RestrictedLockUtils;
     68 import com.android.settingslib.wifi.AccessPoint;
     69 import com.android.settingslib.wifi.AccessPoint.AccessPointListener;
     70 import com.android.settingslib.wifi.AccessPointPreference;
     71 import com.android.settingslib.wifi.WifiTracker;
     72 import com.android.settingslib.wifi.WifiTrackerFactory;
     73 
     74 import java.util.ArrayList;
     75 import java.util.List;
     76 
     77 /**
     78  * Two types of UI are provided here.
     79  *
     80  * The first is for "usual Settings", appearing as any other Setup fragment.
     81  *
     82  * The second is for Setup Wizard, with a simplified interface that hides the action bar
     83  * and menus.
     84  */
     85 public class WifiSettings extends RestrictedSettingsFragment
     86         implements Indexable, WifiTracker.WifiListener, AccessPointListener,
     87         WifiDialog.WifiDialogListener {
     88 
     89     private static final String TAG = "WifiSettings";
     90 
     91     private static final int MENU_ID_CONNECT = Menu.FIRST + 6;
     92     private static final int MENU_ID_FORGET = Menu.FIRST + 7;
     93     private static final int MENU_ID_MODIFY = Menu.FIRST + 8;
     94     private static final int MENU_ID_WRITE_NFC = Menu.FIRST + 9;
     95 
     96     public static final int WIFI_DIALOG_ID = 1;
     97     private static final int WRITE_NFC_DIALOG_ID = 6;
     98 
     99     // Instance state keys
    100     private static final String SAVE_DIALOG_MODE = "dialog_mode";
    101     private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state";
    102     private static final String SAVED_WIFI_NFC_DIALOG_STATE = "wifi_nfc_dlg_state";
    103 
    104     private static final String PREF_KEY_EMPTY_WIFI_LIST = "wifi_empty_list";
    105     private static final String PREF_KEY_CONNECTED_ACCESS_POINTS = "connected_access_point";
    106     private static final String PREF_KEY_ACCESS_POINTS = "access_points";
    107     private static final String PREF_KEY_ADDITIONAL_SETTINGS = "additional_settings";
    108     private static final String PREF_KEY_CONFIGURE_WIFI_SETTINGS = "configure_settings";
    109     private static final String PREF_KEY_SAVED_NETWORKS = "saved_networks";
    110 
    111     private static boolean isVerboseLoggingEnabled() {
    112         return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE);
    113     }
    114 
    115     private final Runnable mUpdateAccessPointsRunnable = () -> {
    116         updateAccessPointPreferences();
    117     };
    118     private final Runnable mHideProgressBarRunnable = () -> {
    119         setProgressBarVisible(false);
    120     };
    121 
    122     protected WifiManager mWifiManager;
    123     private ConnectivityManager mConnectivityManager;
    124     private WifiManager.ActionListener mConnectListener;
    125     private WifiManager.ActionListener mSaveListener;
    126     private WifiManager.ActionListener mForgetListener;
    127     private CaptivePortalNetworkCallback mCaptivePortalNetworkCallback;
    128 
    129     /**
    130      * The state of {@link #isUiRestricted()} at {@link #onCreate(Bundle)}}. This is neccesary to
    131      * ensure that behavior is consistent if {@link #isUiRestricted()} changes. It could be changed
    132      * by the Test DPC tool in AFW mode.
    133      */
    134     private boolean mIsRestricted;
    135 
    136     private WifiEnabler mWifiEnabler;
    137     // An access point being edited is stored here.
    138     private AccessPoint mSelectedAccessPoint;
    139 
    140     private WifiDialog mDialog;
    141     private WriteWifiConfigToNfcDialog mWifiToNfcDialog;
    142 
    143     private View mProgressHeader;
    144 
    145     // this boolean extra specifies whether to disable the Next button when not connected. Used by
    146     // account creation outside of setup wizard.
    147     private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect";
    148     // This string extra specifies a network to open the connect dialog on, so the user can enter
    149     // network credentials.  This is used by quick settings for secured networks, among other
    150     // things.
    151     public static final String EXTRA_START_CONNECT_SSID = "wifi_start_connect_ssid";
    152 
    153     // should Next button only be enabled when we have a connection?
    154     private boolean mEnableNextOnConnection;
    155 
    156     // Save the dialog details
    157     private int mDialogMode;
    158     private AccessPoint mDlgAccessPoint;
    159     private Bundle mAccessPointSavedState;
    160     private Bundle mWifiNfcDialogSavedState;
    161 
    162     private WifiTracker mWifiTracker;
    163     private String mOpenSsid;
    164 
    165     private AccessPointPreference.UserBadgeCache mUserBadgeCache;
    166 
    167     private PreferenceCategory mConnectedAccessPointPreferenceCategory;
    168     private PreferenceCategory mAccessPointsPreferenceCategory;
    169     private PreferenceCategory mAdditionalSettingsPreferenceCategory;
    170     private Preference mAddPreference;
    171     private Preference mConfigureWifiSettingsPreference;
    172     private Preference mSavedNetworksPreference;
    173     private LinkablePreference mStatusMessagePreference;
    174 
    175     // For Search
    176     public static final String DATA_KEY_REFERENCE = "main_toggle_wifi";
    177 
    178     /**
    179      * Tracks whether the user initiated a connection via clicking in order to autoscroll to the
    180      * network once connected.
    181      */
    182     private boolean mClickedConnect;
    183 
    184     /* End of "used in Wifi Setup context" */
    185 
    186     public WifiSettings() {
    187         super(DISALLOW_CONFIG_WIFI);
    188     }
    189 
    190     @Override
    191     public void onViewCreated(View view, Bundle savedInstanceState) {
    192         super.onViewCreated(view, savedInstanceState);
    193         final Activity activity = getActivity();
    194         if (activity != null) {
    195             mProgressHeader = setPinnedHeaderView(R.layout.wifi_progress_header)
    196                     .findViewById(R.id.progress_bar_animation);
    197             setProgressBarVisible(false);
    198         }
    199         ((SettingsActivity) activity).getSwitchBar().setSwitchBarText(
    200                 R.string.wifi_settings_master_switch_title,
    201                 R.string.wifi_settings_master_switch_title);
    202     }
    203 
    204     @Override
    205     public void onCreate(Bundle icicle) {
    206         super.onCreate(icicle);
    207 
    208         // TODO(b/37429702): Add animations and preference comparator back after initial screen is
    209         // loaded (ODR).
    210         setAnimationAllowed(false);
    211 
    212         addPreferences();
    213 
    214         mIsRestricted = isUiRestricted();
    215     }
    216 
    217     private void addPreferences() {
    218         addPreferencesFromResource(R.xml.wifi_settings);
    219 
    220         mConnectedAccessPointPreferenceCategory =
    221                 (PreferenceCategory) findPreference(PREF_KEY_CONNECTED_ACCESS_POINTS);
    222         mAccessPointsPreferenceCategory =
    223                 (PreferenceCategory) findPreference(PREF_KEY_ACCESS_POINTS);
    224         mAdditionalSettingsPreferenceCategory =
    225                 (PreferenceCategory) findPreference(PREF_KEY_ADDITIONAL_SETTINGS);
    226         mConfigureWifiSettingsPreference = findPreference(PREF_KEY_CONFIGURE_WIFI_SETTINGS);
    227         mSavedNetworksPreference = findPreference(PREF_KEY_SAVED_NETWORKS);
    228 
    229         Context prefContext = getPrefContext();
    230         mAddPreference = new Preference(prefContext);
    231         mAddPreference.setIcon(R.drawable.ic_menu_add_inset);
    232         mAddPreference.setTitle(R.string.wifi_add_network);
    233         mStatusMessagePreference = new LinkablePreference(prefContext);
    234 
    235         mUserBadgeCache = new AccessPointPreference.UserBadgeCache(getPackageManager());
    236     }
    237 
    238     @Override
    239     public void onActivityCreated(Bundle savedInstanceState) {
    240         super.onActivityCreated(savedInstanceState);
    241 
    242         mWifiTracker = WifiTrackerFactory.create(
    243                 getActivity(), this, getLifecycle(), true, true);
    244         mWifiManager = mWifiTracker.getManager();
    245 
    246         final Activity activity = getActivity();
    247         if (activity != null) {
    248             mConnectivityManager = getActivity().getSystemService(ConnectivityManager.class);
    249         }
    250 
    251         mConnectListener = new WifiManager.ActionListener() {
    252                                    @Override
    253                                    public void onSuccess() {
    254                                    }
    255                                    @Override
    256                                    public void onFailure(int reason) {
    257                                        Activity activity = getActivity();
    258                                        if (activity != null) {
    259                                            Toast.makeText(activity,
    260                                                 R.string.wifi_failed_connect_message,
    261                                                 Toast.LENGTH_SHORT).show();
    262                                        }
    263                                    }
    264                                };
    265 
    266         mSaveListener = new WifiManager.ActionListener() {
    267                                 @Override
    268                                 public void onSuccess() {
    269                                 }
    270                                 @Override
    271                                 public void onFailure(int reason) {
    272                                     Activity activity = getActivity();
    273                                     if (activity != null) {
    274                                         Toast.makeText(activity,
    275                                             R.string.wifi_failed_save_message,
    276                                             Toast.LENGTH_SHORT).show();
    277                                     }
    278                                 }
    279                             };
    280 
    281         mForgetListener = new WifiManager.ActionListener() {
    282                                    @Override
    283                                    public void onSuccess() {
    284                                    }
    285                                    @Override
    286                                    public void onFailure(int reason) {
    287                                        Activity activity = getActivity();
    288                                        if (activity != null) {
    289                                            Toast.makeText(activity,
    290                                                R.string.wifi_failed_forget_message,
    291                                                Toast.LENGTH_SHORT).show();
    292                                        }
    293                                    }
    294                                };
    295 
    296         if (savedInstanceState != null) {
    297             mDialogMode = savedInstanceState.getInt(SAVE_DIALOG_MODE);
    298             if (savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) {
    299                 mAccessPointSavedState =
    300                     savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE);
    301             }
    302 
    303             if (savedInstanceState.containsKey(SAVED_WIFI_NFC_DIALOG_STATE)) {
    304                 mWifiNfcDialogSavedState =
    305                     savedInstanceState.getBundle(SAVED_WIFI_NFC_DIALOG_STATE);
    306             }
    307         }
    308 
    309         // if we're supposed to enable/disable the Next button based on our current connection
    310         // state, start it off in the right state
    311         Intent intent = getActivity().getIntent();
    312         mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false);
    313 
    314         if (mEnableNextOnConnection) {
    315             if (hasNextButton()) {
    316                 final ConnectivityManager connectivity = (ConnectivityManager)
    317                         getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
    318                 if (connectivity != null) {
    319                     NetworkInfo info = connectivity.getNetworkInfo(
    320                             ConnectivityManager.TYPE_WIFI);
    321                     changeNextButtonState(info.isConnected());
    322                 }
    323             }
    324         }
    325 
    326         registerForContextMenu(getListView());
    327         setHasOptionsMenu(true);
    328 
    329         if (intent.hasExtra(EXTRA_START_CONNECT_SSID)) {
    330             mOpenSsid = intent.getStringExtra(EXTRA_START_CONNECT_SSID);
    331         }
    332     }
    333 
    334     @Override
    335     public void onDestroyView() {
    336         super.onDestroyView();
    337 
    338         if (mWifiEnabler != null) {
    339             mWifiEnabler.teardownSwitchController();
    340         }
    341     }
    342 
    343     @Override
    344     public void onStart() {
    345         super.onStart();
    346 
    347         // On/off switch is hidden for Setup Wizard (returns null)
    348         mWifiEnabler = createWifiEnabler();
    349 
    350         if (mIsRestricted) {
    351             restrictUi();
    352             return;
    353         }
    354 
    355         onWifiStateChanged(mWifiManager.getWifiState());
    356     }
    357 
    358     private void restrictUi() {
    359         if (!isUiRestrictedByOnlyAdmin()) {
    360             getEmptyTextView().setText(R.string.wifi_empty_list_user_restricted);
    361         }
    362         getPreferenceScreen().removeAll();
    363     }
    364 
    365     /**
    366      * @return new WifiEnabler or null (as overridden by WifiSettingsForSetupWizard)
    367      */
    368     private WifiEnabler createWifiEnabler() {
    369         final SettingsActivity activity = (SettingsActivity) getActivity();
    370         return new WifiEnabler(activity, new SwitchBarController(activity.getSwitchBar()),
    371             mMetricsFeatureProvider);
    372     }
    373 
    374     @Override
    375     public void onResume() {
    376         final Activity activity = getActivity();
    377         super.onResume();
    378 
    379         // Because RestrictedSettingsFragment's onResume potentially requests authorization,
    380         // which changes the restriction state, recalculate it.
    381         final boolean alreadyImmutablyRestricted = mIsRestricted;
    382         mIsRestricted = isUiRestricted();
    383         if (!alreadyImmutablyRestricted && mIsRestricted) {
    384             restrictUi();
    385         }
    386 
    387         if (mWifiEnabler != null) {
    388             mWifiEnabler.resume(activity);
    389         }
    390     }
    391 
    392     @Override
    393     public void onPause() {
    394         super.onPause();
    395         if (mWifiEnabler != null) {
    396             mWifiEnabler.pause();
    397         }
    398     }
    399 
    400     @Override
    401     public void onStop() {
    402         getView().removeCallbacks(mUpdateAccessPointsRunnable);
    403         getView().removeCallbacks(mHideProgressBarRunnable);
    404         unregisterCaptivePortalNetworkCallback();
    405         super.onStop();
    406     }
    407 
    408     @Override
    409     public void onActivityResult(int requestCode, int resultCode, Intent data) {
    410         super.onActivityResult(requestCode, resultCode, data);
    411 
    412         final boolean formerlyRestricted = mIsRestricted;
    413         mIsRestricted = isUiRestricted();
    414         if (formerlyRestricted && !mIsRestricted
    415                 && getPreferenceScreen().getPreferenceCount() == 0) {
    416             // De-restrict the ui
    417             addPreferences();
    418         }
    419     }
    420 
    421     @Override
    422     public int getMetricsCategory() {
    423         return MetricsEvent.WIFI;
    424     }
    425 
    426     @Override
    427     public void onSaveInstanceState(Bundle outState) {
    428         super.onSaveInstanceState(outState);
    429 
    430         // If the dialog is showing, save its state.
    431         if (mDialog != null && mDialog.isShowing()) {
    432             outState.putInt(SAVE_DIALOG_MODE, mDialogMode);
    433             if (mDlgAccessPoint != null) {
    434                 mAccessPointSavedState = new Bundle();
    435                 mDlgAccessPoint.saveWifiState(mAccessPointSavedState);
    436                 outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState);
    437             }
    438         }
    439 
    440         if (mWifiToNfcDialog != null && mWifiToNfcDialog.isShowing()) {
    441             Bundle savedState = new Bundle();
    442             mWifiToNfcDialog.saveState(savedState);
    443             outState.putBundle(SAVED_WIFI_NFC_DIALOG_STATE, savedState);
    444         }
    445     }
    446 
    447     @Override
    448     public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
    449             Preference preference = (Preference) view.getTag();
    450 
    451             if (preference instanceof LongPressAccessPointPreference) {
    452                 mSelectedAccessPoint =
    453                         ((LongPressAccessPointPreference) preference).getAccessPoint();
    454                 menu.setHeaderTitle(mSelectedAccessPoint.getSsid());
    455                 if (mSelectedAccessPoint.isConnectable()) {
    456                     menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
    457                 }
    458 
    459                 WifiConfiguration config = mSelectedAccessPoint.getConfig();
    460                 // Some configs are ineditable
    461                 if (WifiUtils.isNetworkLockedDown(getActivity(), config)) {
    462                     return;
    463                 }
    464 
    465                 if (mSelectedAccessPoint.isSaved() || mSelectedAccessPoint.isEphemeral()) {
    466                     // Allow forgetting a network if either the network is saved or ephemerally
    467                     // connected. (In the latter case, "forget" blacklists the network so it won't
    468                     // be used again, ephemerally).
    469                     menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget);
    470                 }
    471                 if (mSelectedAccessPoint.isSaved()) {
    472                     menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);
    473                     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
    474                     if (nfcAdapter != null && nfcAdapter.isEnabled() &&
    475                             mSelectedAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
    476                         // Only allow writing of NFC tags for password-protected networks.
    477                         menu.add(Menu.NONE, MENU_ID_WRITE_NFC, 0, R.string.wifi_menu_write_to_nfc);
    478                     }
    479                 }
    480             }
    481     }
    482 
    483     @Override
    484     public boolean onContextItemSelected(MenuItem item) {
    485         if (mSelectedAccessPoint == null) {
    486             return super.onContextItemSelected(item);
    487         }
    488         switch (item.getItemId()) {
    489             case MENU_ID_CONNECT: {
    490                 boolean isSavedNetwork = mSelectedAccessPoint.isSaved();
    491                 if (isSavedNetwork) {
    492                     connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
    493                 } else if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
    494                     /** Bypass dialog for unsecured networks */
    495                     mSelectedAccessPoint.generateOpenNetworkConfig();
    496                     connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
    497                 } else {
    498                     showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);
    499                 }
    500                 return true;
    501             }
    502             case MENU_ID_FORGET: {
    503                 forget();
    504                 return true;
    505             }
    506             case MENU_ID_MODIFY: {
    507                 showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_MODIFY);
    508                 return true;
    509             }
    510             case MENU_ID_WRITE_NFC:
    511                 showDialog(WRITE_NFC_DIALOG_ID);
    512                 return true;
    513 
    514         }
    515         return super.onContextItemSelected(item);
    516     }
    517 
    518     @Override
    519     public boolean onPreferenceTreeClick(Preference preference) {
    520         // If the preference has a fragment set, open that
    521         if (preference.getFragment() != null) {
    522             preference.setOnPreferenceClickListener(null);
    523             return super.onPreferenceTreeClick(preference);
    524         }
    525 
    526         if (preference instanceof LongPressAccessPointPreference) {
    527             mSelectedAccessPoint = ((LongPressAccessPointPreference) preference).getAccessPoint();
    528             if (mSelectedAccessPoint == null) {
    529                 return false;
    530             }
    531             if (mSelectedAccessPoint.isActive()) {
    532                 return super.onPreferenceTreeClick(preference);
    533             }
    534             /**
    535              * Bypass dialog and connect to unsecured networks, or previously connected saved
    536              * networks, or Passpoint provided networks.
    537              */
    538             WifiConfiguration config = mSelectedAccessPoint.getConfig();
    539             if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
    540                 mSelectedAccessPoint.generateOpenNetworkConfig();
    541                 connect(mSelectedAccessPoint.getConfig(), mSelectedAccessPoint.isSaved());
    542             } else if (mSelectedAccessPoint.isSaved() && config != null
    543                     && config.getNetworkSelectionStatus() != null
    544                     && config.getNetworkSelectionStatus().getHasEverConnected()) {
    545                 connect(config, true /* isSavedNetwork */);
    546             } else if (mSelectedAccessPoint.isPasspoint()) {
    547                 // Access point provided by an installed Passpoint provider, connect using
    548                 // the associated config.
    549                 connect(config, true /* isSavedNetwork */);
    550             } else {
    551                 showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);
    552             }
    553         } else if (preference == mAddPreference) {
    554             onAddNetworkPressed();
    555         } else {
    556             return super.onPreferenceTreeClick(preference);
    557         }
    558         return true;
    559     }
    560 
    561     private void showDialog(AccessPoint accessPoint, int dialogMode) {
    562         if (accessPoint != null) {
    563             WifiConfiguration config = accessPoint.getConfig();
    564             if (WifiUtils.isNetworkLockedDown(getActivity(), config) && accessPoint.isActive()) {
    565                 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(),
    566                         RestrictedLockUtils.getDeviceOwner(getActivity()));
    567                 return;
    568             }
    569         }
    570 
    571         if (mDialog != null) {
    572             removeDialog(WIFI_DIALOG_ID);
    573             mDialog = null;
    574         }
    575 
    576         // Save the access point and edit mode
    577         mDlgAccessPoint = accessPoint;
    578         mDialogMode = dialogMode;
    579 
    580         showDialog(WIFI_DIALOG_ID);
    581     }
    582 
    583     @Override
    584     public Dialog onCreateDialog(int dialogId) {
    585         switch (dialogId) {
    586             case WIFI_DIALOG_ID:
    587                 if (mDlgAccessPoint == null && mAccessPointSavedState == null) {
    588                     // add new network
    589                     mDialog = WifiDialog
    590                             .createFullscreen(getActivity(), this, mDlgAccessPoint, mDialogMode);
    591                 } else {
    592                     // modify network
    593                     if (mDlgAccessPoint == null) {
    594                         // restore AP from save state
    595                         mDlgAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState);
    596                         // Reset the saved access point data
    597                         mAccessPointSavedState = null;
    598                     }
    599                     mDialog = WifiDialog
    600                             .createModal(getActivity(), this, mDlgAccessPoint, mDialogMode);
    601                 }
    602 
    603                 mSelectedAccessPoint = mDlgAccessPoint;
    604                 return mDialog;
    605             case WRITE_NFC_DIALOG_ID:
    606                 if (mSelectedAccessPoint != null) {
    607                     mWifiToNfcDialog = new WriteWifiConfigToNfcDialog(
    608                             getActivity(),
    609                             mSelectedAccessPoint.getSecurity());
    610                 } else if (mWifiNfcDialogSavedState != null) {
    611                     mWifiToNfcDialog = new WriteWifiConfigToNfcDialog(getActivity(),
    612                             mWifiNfcDialogSavedState);
    613                 }
    614 
    615                 return mWifiToNfcDialog;
    616         }
    617         return super.onCreateDialog(dialogId);
    618     }
    619 
    620     @Override
    621     public int getDialogMetricsCategory(int dialogId) {
    622         switch (dialogId) {
    623             case WIFI_DIALOG_ID:
    624                 return MetricsEvent.DIALOG_WIFI_AP_EDIT;
    625             case WRITE_NFC_DIALOG_ID:
    626                 return MetricsEvent.DIALOG_WIFI_WRITE_NFC;
    627             default:
    628                 return 0;
    629         }
    630     }
    631 
    632     /**
    633      * Called to indicate the list of AccessPoints has been updated and
    634      * getAccessPoints should be called to get the latest information.
    635      */
    636     @Override
    637     public void onAccessPointsChanged() {
    638         Log.d(TAG, "onAccessPointsChanged (WifiTracker) callback initiated");
    639         updateAccessPointsDelayed();
    640     }
    641 
    642     /**
    643      * Updates access points from {@link WifiManager#getScanResults()}. Adds a delay to have
    644      * progress bar displayed before starting to modify APs.
    645      */
    646     private void updateAccessPointsDelayed() {
    647         // Safeguard from some delayed event handling
    648         if (getActivity() != null && !mIsRestricted && mWifiManager.isWifiEnabled()) {
    649             final View view = getView();
    650             final Handler handler = view.getHandler();
    651             if (handler != null && handler.hasCallbacks(mUpdateAccessPointsRunnable)) {
    652                 return;
    653             }
    654             setProgressBarVisible(true);
    655             view.postDelayed(mUpdateAccessPointsRunnable, 300 /* delay milliseconds */);
    656         }
    657     }
    658 
    659     /** Called when the state of Wifi has changed. */
    660     @Override
    661     public void onWifiStateChanged(int state) {
    662         if (mIsRestricted) {
    663             return;
    664         }
    665 
    666         final int wifiState = mWifiManager.getWifiState();
    667         switch (wifiState) {
    668             case WifiManager.WIFI_STATE_ENABLED:
    669                 updateAccessPointPreferences();
    670                 break;
    671 
    672             case WifiManager.WIFI_STATE_ENABLING:
    673                 removeConnectedAccessPointPreference();
    674                 mAccessPointsPreferenceCategory.removeAll();
    675                 addMessagePreference(R.string.wifi_starting);
    676                 setProgressBarVisible(true);
    677                 break;
    678 
    679             case WifiManager.WIFI_STATE_DISABLING:
    680                 removeConnectedAccessPointPreference();
    681                 mAccessPointsPreferenceCategory.removeAll();
    682                 addMessagePreference(R.string.wifi_stopping);
    683                 break;
    684 
    685             case WifiManager.WIFI_STATE_DISABLED:
    686                 setOffMessage();
    687                 setAdditionalSettingsSummaries();
    688                 setProgressBarVisible(false);
    689                 break;
    690         }
    691     }
    692 
    693     /**
    694      * Called when the connection state of wifi has changed.
    695      */
    696     @Override
    697     public void onConnectedChanged() {
    698         changeNextButtonState(mWifiTracker.isConnected());
    699     }
    700 
    701     /** Helper method to return whether an AccessPoint is disabled due to a wrong password */
    702     private static boolean isDisabledByWrongPassword(AccessPoint accessPoint) {
    703         WifiConfiguration config = accessPoint.getConfig();
    704         if (config == null) {
    705             return false;
    706         }
    707         WifiConfiguration.NetworkSelectionStatus networkStatus =
    708                 config.getNetworkSelectionStatus();
    709         if (networkStatus == null || networkStatus.isNetworkEnabled()) {
    710             return false;
    711         }
    712         int reason = networkStatus.getNetworkSelectionDisableReason();
    713         return WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD == reason;
    714     }
    715 
    716     private void updateAccessPointPreferences() {
    717         // in case state has changed
    718         if (!mWifiManager.isWifiEnabled()) {
    719             return;
    720         }
    721         // AccessPoints are sorted by the WifiTracker
    722         final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
    723         if (isVerboseLoggingEnabled()) {
    724             Log.i(TAG, "updateAccessPoints called for: " + accessPoints);
    725         }
    726 
    727         boolean hasAvailableAccessPoints = false;
    728         mAccessPointsPreferenceCategory.removePreference(mStatusMessagePreference);
    729         cacheRemoveAllPrefs(mAccessPointsPreferenceCategory);
    730 
    731         int index =
    732                 configureConnectedAccessPointPreferenceCategory(accessPoints) ? 1 : 0;
    733         int numAccessPoints = accessPoints.size();
    734         for (; index < numAccessPoints; index++) {
    735             AccessPoint accessPoint = accessPoints.get(index);
    736             // Ignore access points that are out of range.
    737             if (accessPoint.isReachable()) {
    738                 String key = accessPoint.getKey();
    739                 hasAvailableAccessPoints = true;
    740                 LongPressAccessPointPreference pref =
    741                         (LongPressAccessPointPreference) getCachedPreference(key);
    742                 if (pref != null) {
    743                     pref.setOrder(index);
    744                     continue;
    745                 }
    746                 LongPressAccessPointPreference preference =
    747                         createLongPressAccessPointPreference(accessPoint);
    748                 preference.setKey(key);
    749                 preference.setOrder(index);
    750                 if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr())
    751                         && accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
    752                     if (!accessPoint.isSaved() || isDisabledByWrongPassword(accessPoint)) {
    753                         onPreferenceTreeClick(preference);
    754                         mOpenSsid = null;
    755                     }
    756                 }
    757                 mAccessPointsPreferenceCategory.addPreference(preference);
    758                 accessPoint.setListener(WifiSettings.this);
    759                 preference.refresh();
    760             }
    761         }
    762         removeCachedPrefs(mAccessPointsPreferenceCategory);
    763         mAddPreference.setOrder(index);
    764         mAccessPointsPreferenceCategory.addPreference(mAddPreference);
    765         setAdditionalSettingsSummaries();
    766 
    767         if (!hasAvailableAccessPoints) {
    768             setProgressBarVisible(true);
    769             Preference pref = new Preference(getPrefContext());
    770             pref.setSelectable(false);
    771             pref.setSummary(R.string.wifi_empty_list_wifi_on);
    772             pref.setOrder(index++);
    773             pref.setKey(PREF_KEY_EMPTY_WIFI_LIST);
    774             mAccessPointsPreferenceCategory.addPreference(pref);
    775         } else {
    776             // Continuing showing progress bar for an additional delay to overlap with animation
    777             getView().postDelayed(mHideProgressBarRunnable, 1700 /* delay millis */);
    778         }
    779     }
    780 
    781     @NonNull
    782     private LongPressAccessPointPreference createLongPressAccessPointPreference(
    783             AccessPoint accessPoint) {
    784         return new LongPressAccessPointPreference(accessPoint, getPrefContext(), mUserBadgeCache,
    785                 false /* forSavedNetworks */, R.drawable.ic_wifi_signal_0, this);
    786     }
    787 
    788     @NonNull
    789     private ConnectedAccessPointPreference createConnectedAccessPointPreference(
    790             AccessPoint accessPoint) {
    791         return new ConnectedAccessPointPreference(accessPoint, getPrefContext(), mUserBadgeCache,
    792                 R.drawable.ic_wifi_signal_0, false /* forSavedNetworks */);
    793     }
    794 
    795     /**
    796      * Configure the ConnectedAccessPointPreferenceCategory and return true if the Category was
    797      * shown.
    798      */
    799     private boolean configureConnectedAccessPointPreferenceCategory(
    800             List<AccessPoint> accessPoints) {
    801         if (accessPoints.size() == 0) {
    802             removeConnectedAccessPointPreference();
    803             return false;
    804         }
    805 
    806         AccessPoint connectedAp = accessPoints.get(0);
    807         if (!connectedAp.isActive()) {
    808             removeConnectedAccessPointPreference();
    809             return false;
    810         }
    811 
    812         // Is the preference category empty?
    813         if (mConnectedAccessPointPreferenceCategory.getPreferenceCount() == 0) {
    814             addConnectedAccessPointPreference(connectedAp);
    815             return true;
    816         }
    817 
    818         // Is the previous currently connected SSID different from the new one?
    819         ConnectedAccessPointPreference preference =
    820                 (ConnectedAccessPointPreference)
    821                         (mConnectedAccessPointPreferenceCategory.getPreference(0));
    822         // The AccessPoints need to be the same reference to ensure that updates are reflected
    823         // in the UI.
    824         if (preference.getAccessPoint() != connectedAp) {
    825             removeConnectedAccessPointPreference();
    826             addConnectedAccessPointPreference(connectedAp);
    827             return true;
    828         }
    829 
    830         // Else same AP is connected, simply refresh the connected access point preference
    831         // (first and only access point in this category).
    832         preference.refresh();
    833         // Update any potential changes to the connected network and ensure that the callback is
    834         // registered after an onStop lifecycle event.
    835         registerCaptivePortalNetworkCallback(getCurrentWifiNetwork(), preference);
    836         return true;
    837     }
    838 
    839     /**
    840      * Creates a Preference for the given {@link AccessPoint} and adds it to the
    841      * {@link #mConnectedAccessPointPreferenceCategory}.
    842      */
    843     private void addConnectedAccessPointPreference(AccessPoint connectedAp) {
    844         final ConnectedAccessPointPreference pref =
    845                 createConnectedAccessPointPreference(connectedAp);
    846         registerCaptivePortalNetworkCallback(getCurrentWifiNetwork(), pref);
    847 
    848         // Launch details page or captive portal on click.
    849         pref.setOnPreferenceClickListener(
    850                 preference -> {
    851                     pref.getAccessPoint().saveWifiState(pref.getExtras());
    852                     if (mCaptivePortalNetworkCallback != null
    853                             && mCaptivePortalNetworkCallback.isCaptivePortal()) {
    854                         mConnectivityManager.startCaptivePortalApp(
    855                                 mCaptivePortalNetworkCallback.getNetwork());
    856                     } else {
    857                         launchNetworkDetailsFragment(pref);
    858                     }
    859                     return true;
    860                 });
    861 
    862         pref.setOnGearClickListener(
    863                 preference -> {
    864                     pref.getAccessPoint().saveWifiState(pref.getExtras());
    865                     launchNetworkDetailsFragment(pref);
    866                 });
    867 
    868         pref.refresh();
    869 
    870         mConnectedAccessPointPreferenceCategory.addPreference(pref);
    871         mConnectedAccessPointPreferenceCategory.setVisible(true);
    872         if (mClickedConnect) {
    873             mClickedConnect = false;
    874             scrollToPreference(mConnectedAccessPointPreferenceCategory);
    875         }
    876     }
    877 
    878     private void registerCaptivePortalNetworkCallback(
    879             Network wifiNetwork, ConnectedAccessPointPreference pref) {
    880         if (wifiNetwork == null || pref == null) {
    881             Log.w(TAG, "Network or Preference were null when registering callback.");
    882             return;
    883         }
    884 
    885         if (mCaptivePortalNetworkCallback != null
    886                 && mCaptivePortalNetworkCallback.isSameNetworkAndPreference(wifiNetwork, pref)) {
    887             return;
    888         }
    889 
    890         unregisterCaptivePortalNetworkCallback();
    891 
    892         mCaptivePortalNetworkCallback = new CaptivePortalNetworkCallback(wifiNetwork, pref);
    893         mConnectivityManager.registerNetworkCallback(
    894                 new NetworkRequest.Builder()
    895                         .clearCapabilities()
    896                         .addTransportType(TRANSPORT_WIFI)
    897                         .build(),
    898                 mCaptivePortalNetworkCallback,
    899                 new Handler(Looper.getMainLooper()));
    900     }
    901 
    902     private void unregisterCaptivePortalNetworkCallback() {
    903         if (mCaptivePortalNetworkCallback != null) {
    904             try {
    905                 mConnectivityManager.unregisterNetworkCallback(mCaptivePortalNetworkCallback);
    906             } catch (RuntimeException e) {
    907                 Log.e(TAG, "Unregistering CaptivePortalNetworkCallback failed.", e);
    908             }
    909             mCaptivePortalNetworkCallback = null;
    910         }
    911     }
    912 
    913     private void launchNetworkDetailsFragment(ConnectedAccessPointPreference pref) {
    914         new SubSettingLauncher(getContext())
    915                 .setTitle(R.string.pref_title_network_details)
    916                 .setDestination(WifiNetworkDetailsFragment.class.getName())
    917                 .setArguments(pref.getExtras())
    918                 .setSourceMetricsCategory(getMetricsCategory())
    919                 .launch();
    920     }
    921 
    922     private Network getCurrentWifiNetwork() {
    923         return mWifiManager != null ? mWifiManager.getCurrentNetwork() : null;
    924     }
    925 
    926     /** Removes all preferences and hide the {@link #mConnectedAccessPointPreferenceCategory}. */
    927     private void removeConnectedAccessPointPreference() {
    928         mConnectedAccessPointPreferenceCategory.removeAll();
    929         mConnectedAccessPointPreferenceCategory.setVisible(false);
    930         unregisterCaptivePortalNetworkCallback();
    931     }
    932 
    933     private void setAdditionalSettingsSummaries() {
    934         mAdditionalSettingsPreferenceCategory.addPreference(mConfigureWifiSettingsPreference);
    935         mConfigureWifiSettingsPreference.setSummary(getString(
    936                 isWifiWakeupEnabled()
    937                         ? R.string.wifi_configure_settings_preference_summary_wakeup_on
    938                         : R.string.wifi_configure_settings_preference_summary_wakeup_off));
    939         int numSavedNetworks = mWifiTracker.getNumSavedNetworks();
    940         if (numSavedNetworks > 0) {
    941             mAdditionalSettingsPreferenceCategory.addPreference(mSavedNetworksPreference);
    942             mSavedNetworksPreference.setSummary(
    943                     getResources().getQuantityString(R.plurals.wifi_saved_access_points_summary,
    944                             numSavedNetworks, numSavedNetworks));
    945         } else {
    946             mAdditionalSettingsPreferenceCategory.removePreference(mSavedNetworksPreference);
    947         }
    948     }
    949 
    950     private boolean isWifiWakeupEnabled() {
    951         PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
    952         ContentResolver contentResolver = getContentResolver();
    953         return Settings.Global.getInt(contentResolver,
    954                         Settings.Global.WIFI_WAKEUP_ENABLED, 0) == 1
    955                 && Settings.Global.getInt(contentResolver,
    956                         Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1
    957                 && Settings.Global.getInt(contentResolver,
    958                         Settings.Global.AIRPLANE_MODE_ON, 0) == 0
    959                 && !powerManager.isPowerSaveMode();
    960     }
    961 
    962     private void setOffMessage() {
    963         final CharSequence title = getText(R.string.wifi_empty_list_wifi_off);
    964         // Don't use WifiManager.isScanAlwaysAvailable() to check the Wi-Fi scanning mode. Instead,
    965         // read the system settings directly. Because when the device is in Airplane mode, even if
    966         // Wi-Fi scanning mode is on, WifiManager.isScanAlwaysAvailable() still returns "off".
    967         final boolean wifiScanningMode = Settings.Global.getInt(getActivity().getContentResolver(),
    968                 Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1;
    969         final CharSequence description = wifiScanningMode ? getText(R.string.wifi_scan_notify_text)
    970                 : getText(R.string.wifi_scan_notify_text_scanning_off);
    971         final LinkifyUtils.OnClickListener clickListener =
    972                 () -> new SubSettingLauncher(getContext())
    973                         .setDestination(ScanningSettings.class.getName())
    974                         .setTitle(R.string.location_scanning_screen_title)
    975                         .setSourceMetricsCategory(getMetricsCategory())
    976                         .launch();
    977         mStatusMessagePreference.setText(title, description, clickListener);
    978         removeConnectedAccessPointPreference();
    979         mAccessPointsPreferenceCategory.removeAll();
    980         mAccessPointsPreferenceCategory.addPreference(mStatusMessagePreference);
    981     }
    982 
    983     private void addMessagePreference(int messageId) {
    984         mStatusMessagePreference.setTitle(messageId);
    985         removeConnectedAccessPointPreference();
    986         mAccessPointsPreferenceCategory.removeAll();
    987         mAccessPointsPreferenceCategory.addPreference(mStatusMessagePreference);
    988     }
    989 
    990     protected void setProgressBarVisible(boolean visible) {
    991         if (mProgressHeader != null) {
    992             mProgressHeader.setVisibility(visible ? View.VISIBLE : View.GONE);
    993         }
    994     }
    995 
    996     /**
    997      * Renames/replaces "Next" button when appropriate. "Next" button usually exists in
    998      * Wifi setup screens, not in usual wifi settings screen.
    999      *
   1000      * @param enabled true when the device is connected to a wifi network.
   1001      */
   1002     private void changeNextButtonState(boolean enabled) {
   1003         if (mEnableNextOnConnection && hasNextButton()) {
   1004             getNextButton().setEnabled(enabled);
   1005         }
   1006     }
   1007 
   1008     @Override
   1009     public void onForget(WifiDialog dialog) {
   1010         forget();
   1011     }
   1012 
   1013     @Override
   1014     public void onSubmit(WifiDialog dialog) {
   1015         if (mDialog != null) {
   1016             submit(mDialog.getController());
   1017         }
   1018     }
   1019 
   1020     /* package */ void submit(WifiConfigController configController) {
   1021 
   1022         final WifiConfiguration config = configController.getConfig();
   1023 
   1024         if (config == null) {
   1025             if (mSelectedAccessPoint != null
   1026                     && mSelectedAccessPoint.isSaved()) {
   1027                 connect(mSelectedAccessPoint.getConfig(), true /* isSavedNetwork */);
   1028             }
   1029         } else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) {
   1030             mWifiManager.save(config, mSaveListener);
   1031         } else {
   1032             mWifiManager.save(config, mSaveListener);
   1033             if (mSelectedAccessPoint != null) { // Not an "Add network"
   1034                 connect(config, false /* isSavedNetwork */);
   1035             }
   1036         }
   1037 
   1038         mWifiTracker.resumeScanning();
   1039     }
   1040 
   1041     /* package */ void forget() {
   1042         mMetricsFeatureProvider.action(getActivity(), MetricsEvent.ACTION_WIFI_FORGET);
   1043         if (!mSelectedAccessPoint.isSaved()) {
   1044             if (mSelectedAccessPoint.getNetworkInfo() != null &&
   1045                     mSelectedAccessPoint.getNetworkInfo().getState() != State.DISCONNECTED) {
   1046                 // Network is active but has no network ID - must be ephemeral.
   1047                 mWifiManager.disableEphemeralNetwork(
   1048                         AccessPoint.convertToQuotedString(mSelectedAccessPoint.getSsidStr()));
   1049             } else {
   1050                 // Should not happen, but a monkey seems to trigger it
   1051                 Log.e(TAG, "Failed to forget invalid network " + mSelectedAccessPoint.getConfig());
   1052                 return;
   1053             }
   1054         } else if (mSelectedAccessPoint.getConfig().isPasspoint()) {
   1055             mWifiManager.removePasspointConfiguration(mSelectedAccessPoint.getConfig().FQDN);
   1056         } else {
   1057             mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId, mForgetListener);
   1058         }
   1059 
   1060         mWifiTracker.resumeScanning();
   1061 
   1062         // We need to rename/replace "Next" button in wifi setup context.
   1063         changeNextButtonState(false);
   1064     }
   1065 
   1066     protected void connect(final WifiConfiguration config, boolean isSavedNetwork) {
   1067         // Log subtype if configuration is a saved network.
   1068         mMetricsFeatureProvider.action(getVisibilityLogger(), MetricsEvent.ACTION_WIFI_CONNECT,
   1069                 isSavedNetwork);
   1070         mWifiManager.connect(config, mConnectListener);
   1071         mClickedConnect = true;
   1072     }
   1073 
   1074     protected void connect(final int networkId, boolean isSavedNetwork) {
   1075         // Log subtype if configuration is a saved network.
   1076         mMetricsFeatureProvider.action(getActivity(), MetricsEvent.ACTION_WIFI_CONNECT,
   1077                 isSavedNetwork);
   1078         mWifiManager.connect(networkId, mConnectListener);
   1079     }
   1080 
   1081     /**
   1082      * Called when "add network" button is pressed.
   1083      */
   1084     /* package */ void onAddNetworkPressed() {
   1085         mMetricsFeatureProvider.action(getActivity(), MetricsEvent.ACTION_WIFI_ADD_NETWORK);
   1086         // No exact access point is selected.
   1087         mSelectedAccessPoint = null;
   1088         showDialog(null, WifiConfigUiBase.MODE_CONNECT);
   1089     }
   1090 
   1091     @Override
   1092     public int getHelpResource() {
   1093         return R.string.help_url_wifi;
   1094     }
   1095 
   1096     @Override
   1097     public void onAccessPointChanged(final AccessPoint accessPoint) {
   1098         Log.d(TAG, "onAccessPointChanged (singular) callback initiated");
   1099         View view = getView();
   1100         if (view != null) {
   1101             view.post(new Runnable() {
   1102                 @Override
   1103                 public void run() {
   1104                     Object tag = accessPoint.getTag();
   1105                     if (tag != null) {
   1106                         ((AccessPointPreference) tag).refresh();
   1107                     }
   1108                 }
   1109             });
   1110         }
   1111     }
   1112 
   1113     @Override
   1114     public void onLevelChanged(AccessPoint accessPoint) {
   1115         ((AccessPointPreference) accessPoint.getTag()).onLevelChanged();
   1116     }
   1117 
   1118     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
   1119         new BaseSearchIndexProvider() {
   1120             @Override
   1121             public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
   1122                 final List<SearchIndexableRaw> result = new ArrayList<>();
   1123                 final Resources res = context.getResources();
   1124 
   1125                 // Add fragment title if we are showing this fragment
   1126                 if (res.getBoolean(R.bool.config_show_wifi_settings)) {
   1127                     SearchIndexableRaw data = new SearchIndexableRaw(context);
   1128                     data.title = res.getString(R.string.wifi_settings);
   1129                     data.screenTitle = res.getString(R.string.wifi_settings);
   1130                     data.keywords = res.getString(R.string.keywords_wifi);
   1131                     data.key = DATA_KEY_REFERENCE;
   1132                     result.add(data);
   1133                 }
   1134 
   1135                 return result;
   1136             }
   1137         };
   1138 
   1139     private static class SummaryProvider
   1140             implements SummaryLoader.SummaryProvider, OnSummaryChangeListener {
   1141 
   1142         private final Context mContext;
   1143         private final SummaryLoader mSummaryLoader;
   1144 
   1145         @VisibleForTesting
   1146         WifiSummaryUpdater mSummaryHelper;
   1147 
   1148         public SummaryProvider(Context context, SummaryLoader summaryLoader) {
   1149             mContext = context;
   1150             mSummaryLoader = summaryLoader;
   1151             mSummaryHelper = new WifiSummaryUpdater(mContext, this);
   1152         }
   1153 
   1154 
   1155         @Override
   1156         public void setListening(boolean listening) {
   1157             mSummaryHelper.register(listening);
   1158         }
   1159 
   1160         @Override
   1161         public void onSummaryChanged(String summary) {
   1162             mSummaryLoader.setSummary(this, summary);
   1163         }
   1164     }
   1165 
   1166     public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
   1167             = new SummaryLoader.SummaryProviderFactory() {
   1168         @Override
   1169         public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity,
   1170                                                                    SummaryLoader summaryLoader) {
   1171             return new SummaryProvider(activity, summaryLoader);
   1172         }
   1173     };
   1174 }
   1175