• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.network;
18 
19 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED;
20 import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
21 
22 import android.app.Activity;
23 import android.app.Dialog;
24 import android.app.settings.SettingsEnums;
25 import android.content.ActivityNotFoundException;
26 import android.content.ContentResolver;
27 import android.content.Context;
28 import android.content.DialogInterface;
29 import android.content.Intent;
30 import android.net.NetworkTemplate;
31 import android.net.wifi.WifiConfiguration;
32 import android.net.wifi.WifiManager;
33 import android.os.Bundle;
34 import android.os.Handler;
35 import android.os.PowerManager;
36 import android.provider.Settings;
37 import android.telephony.TelephonyManager;
38 import android.text.TextUtils;
39 import android.util.FeatureFlagUtils;
40 import android.util.Log;
41 import android.view.ContextMenu;
42 import android.view.ContextMenu.ContextMenuInfo;
43 import android.view.Menu;
44 import android.view.MenuInflater;
45 import android.view.MenuItem;
46 import android.view.View;
47 import android.widget.Toast;
48 
49 import androidx.annotation.VisibleForTesting;
50 import androidx.appcompat.app.AlertDialog;
51 import androidx.fragment.app.Fragment;
52 import androidx.preference.Preference;
53 import androidx.preference.PreferenceCategory;
54 import androidx.preference.PreferenceScreen;
55 import androidx.recyclerview.widget.RecyclerView;
56 
57 import com.android.settings.AirplaneModeEnabler;
58 import com.android.settings.R;
59 import com.android.settings.RestrictedSettingsFragment;
60 import com.android.settings.core.FeatureFlags;
61 import com.android.settings.core.SubSettingLauncher;
62 import com.android.settings.datausage.DataUsagePreference;
63 import com.android.settings.datausage.DataUsageUtils;
64 import com.android.settings.search.BaseSearchIndexProvider;
65 import com.android.settings.wifi.AddNetworkFragment;
66 import com.android.settings.wifi.AddWifiNetworkPreference;
67 import com.android.settings.wifi.ConfigureWifiEntryFragment;
68 import com.android.settings.wifi.ConnectedWifiEntryPreference;
69 import com.android.settings.wifi.WifiConfigUiBase2;
70 import com.android.settings.wifi.WifiConnectListener;
71 import com.android.settings.wifi.WifiDialog2;
72 import com.android.settings.wifi.WifiPickerTrackerHelper;
73 import com.android.settings.wifi.WifiUtils;
74 import com.android.settings.wifi.details2.WifiNetworkDetailsFragment2;
75 import com.android.settings.wifi.dpp.WifiDppUtils;
76 import com.android.settingslib.HelpUtils;
77 import com.android.settingslib.RestrictedLockUtils;
78 import com.android.settingslib.RestrictedLockUtilsInternal;
79 import com.android.settingslib.search.Indexable;
80 import com.android.settingslib.search.SearchIndexable;
81 import com.android.settingslib.utils.ThreadUtils;
82 import com.android.settingslib.widget.LayoutPreference;
83 import com.android.settingslib.wifi.LongPressWifiEntryPreference;
84 import com.android.settingslib.wifi.WifiSavedConfigUtils;
85 import com.android.wifitrackerlib.WifiEntry;
86 import com.android.wifitrackerlib.WifiEntry.ConnectCallback;
87 import com.android.wifitrackerlib.WifiPickerTracker;
88 
89 import java.util.List;
90 import java.util.Optional;
91 
92 /**
93  * UI for Mobile network and Wi-Fi network settings.
94  *
95  * TODO(b/167474581): Define the intent android.settings.NETWORK_PROVIDER_SETTINGS in Settings.java.
96  */
97 @SearchIndexable
98 public class NetworkProviderSettings extends RestrictedSettingsFragment
99         implements Indexable, WifiPickerTracker.WifiPickerTrackerCallback,
100         WifiDialog2.WifiDialog2Listener, DialogInterface.OnDismissListener,
101         AirplaneModeEnabler.OnAirplaneModeChangedListener, InternetUpdater.InternetChangeListener {
102 
103     public static final String ACTION_NETWORK_PROVIDER_SETTINGS =
104             "android.settings.NETWORK_PROVIDER_SETTINGS";
105 
106     private static final String TAG = "NetworkProviderSettings";
107     // IDs of context menu
108     static final int MENU_ID_CONNECT = Menu.FIRST + 1;
109     @VisibleForTesting
110     static final int MENU_ID_DISCONNECT = Menu.FIRST + 2;
111     @VisibleForTesting
112     static final int MENU_ID_FORGET = Menu.FIRST + 3;
113     static final int MENU_ID_MODIFY = Menu.FIRST + 4;
114     static final int MENU_FIX_CONNECTIVITY = Menu.FIRST + 5;
115     static final int MENU_ID_SHARE = Menu.FIRST + 6;
116 
117     @VisibleForTesting
118     static final int ADD_NETWORK_REQUEST = 2;
119     static final int CONFIG_NETWORK_REQUEST = 3;
120     static final int MANAGE_SUBSCRIPTION = 4;
121 
122     private static final String PREF_KEY_AIRPLANE_MODE_MSG = "airplane_mode_message";
123     private static final String PREF_KEY_EMPTY_WIFI_LIST = "wifi_empty_list";
124     // TODO(b/70983952): Rename these to use WifiEntry instead of AccessPoint.
125     @VisibleForTesting
126     static final String PREF_KEY_CONNECTED_ACCESS_POINTS = "connected_access_point";
127     @VisibleForTesting
128     static final String PREF_KEY_FIRST_ACCESS_POINTS = "first_access_points";
129     private static final String PREF_KEY_ACCESS_POINTS = "access_points";
130     private static final String PREF_KEY_CONFIGURE_WIFI_SETTINGS = "configure_wifi_settings";
131     private static final String PREF_KEY_SAVED_NETWORKS = "saved_networks";
132     @VisibleForTesting
133     static final String PREF_KEY_DATA_USAGE = "non_carrier_data_usage";
134     private static final String PREF_KEY_RESET_INTERNET = "resetting_your_internet";
135 
136     private static final int REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER = 0;
137 
138     public static final int WIFI_DIALOG_ID = 1;
139 
140     // Instance state keys
141     private static final String SAVE_DIALOG_MODE = "dialog_mode";
142     private static final String SAVE_DIALOG_WIFIENTRY_KEY = "wifi_ap_key";
143 
144     // Cache at onCreateContextMenu and use at onContextItemSelected. Don't use it in other methods.
145     private WifiEntry mSelectedWifiEntry;
146 
147     // Save the dialog details
148     private int mDialogMode;
149     private String mDialogWifiEntryKey;
150     private WifiEntry mDialogWifiEntry;
151 
152     // This boolean extra specifies whether to enable the Next button when connected. Used by
153     // account creation outside of setup wizard.
154     private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect";
155 
156     // Enable the Next button when a Wi-Fi network is connected.
157     private boolean mEnableNextOnConnection;
158 
159     // This string extra specifies a network to open the connect dialog on, so the user can enter
160     // network credentials.  This is used by quick settings for secured networks, among other
161     // things.
162     private static final String EXTRA_START_CONNECT_SSID = "wifi_start_connect_ssid";
163     private String mOpenSsid;
164 
isVerboseLoggingEnabled()165     private static boolean isVerboseLoggingEnabled() {
166         return WifiPickerTracker.isVerboseLoggingEnabled();
167     }
168 
169     private boolean mIsViewLoading;
170     @VisibleForTesting
171     final Runnable mRemoveLoadingRunnable = () -> {
172         if (mIsViewLoading) {
173             setLoading(false, false);
174             mIsViewLoading = false;
175         }
176     };
177 
178     private boolean mIsWifiEntryListStale = true;
179     @VisibleForTesting
180     final Runnable mUpdateWifiEntryPreferencesRunnable = () -> {
181         updateWifiEntryPreferences();
182         getView().postDelayed(mRemoveLoadingRunnable, 10);
183     };
184     @VisibleForTesting
185     final Runnable mHideProgressBarRunnable = () -> {
186         setProgressBarVisible(false);
187     };
188 
189     protected WifiManager mWifiManager;
190     private WifiManager.ActionListener mConnectListener;
191     private WifiManager.ActionListener mSaveListener;
192     private WifiManager.ActionListener mForgetListener;
193 
194     protected InternetResetHelper mInternetResetHelper;
195 
196     /**
197      * The state of {@link #isUiRestricted()} at {@link #onCreate(Bundle)}}. This is necessary to
198      * ensure that behavior is consistent if {@link #isUiRestricted()} changes. It could be changed
199      * by the Test DPC tool in AFW mode.
200      */
201     protected boolean mIsRestricted;
202 
203     @VisibleForTesting
204     AirplaneModeEnabler mAirplaneModeEnabler;
205     @VisibleForTesting
206     WifiPickerTracker mWifiPickerTracker;
207     private WifiPickerTrackerHelper mWifiPickerTrackerHelper;
208     @VisibleForTesting
209     InternetUpdater mInternetUpdater;
210 
211     private WifiDialog2 mDialog;
212 
213     @VisibleForTesting
214     PreferenceCategory mConnectedWifiEntryPreferenceCategory;
215     @VisibleForTesting
216     PreferenceCategory mFirstWifiEntryPreferenceCategory;
217     @VisibleForTesting
218     PreferenceCategory mWifiEntryPreferenceCategory;
219     @VisibleForTesting
220     AddWifiNetworkPreference mAddWifiNetworkPreference;
221     private WifiSwitchPreferenceController mWifiSwitchPreferenceController;
222     @VisibleForTesting
223     Preference mConfigureWifiSettingsPreference;
224     @VisibleForTesting
225     Preference mSavedNetworksPreference;
226     @VisibleForTesting
227     DataUsagePreference mDataUsagePreference;
228     @VisibleForTesting
229     Preference mAirplaneModeMsgPreference;
230     @VisibleForTesting
231     LayoutPreference mResetInternetPreference;
232     @VisibleForTesting
233     ConnectedEthernetNetworkController mConnectedEthernetNetworkController;
234 
235     /**
236      * Mobile networks list for provider model
237      */
238     private static final String PREF_KEY_PROVIDER_MOBILE_NETWORK = "provider_model_mobile_network";
239     private NetworkMobileProviderController mNetworkMobileProviderController;
240 
241     /**
242      * Tracks whether the user initiated a connection via clicking in order to autoscroll to the
243      * network once connected.
244      */
245     private boolean mClickedConnect;
246 
NetworkProviderSettings()247     public NetworkProviderSettings() {
248         super(DISALLOW_CONFIG_WIFI);
249     }
250 
251     @Override
onViewCreated(View view, Bundle savedInstanceState)252     public void onViewCreated(View view, Bundle savedInstanceState) {
253         super.onViewCreated(view, savedInstanceState);
254         Activity activity = getActivity();
255         if (activity == null) {
256             return;
257         }
258 
259         setPinnedHeaderView(R.layout.progress_header);
260         setProgressBarVisible(false);
261 
262         mWifiManager = activity.getSystemService(WifiManager.class);
263         if (mWifiManager != null) {
264             setLoading(true, false);
265             mIsViewLoading = true;
266             getView().postDelayed(mRemoveLoadingRunnable,
267                     mWifiManager.isWifiEnabled() ? 1000 : 100);
268         }
269     }
270 
271     @Override
onCreate(Bundle icicle)272     public void onCreate(Bundle icicle) {
273         super.onCreate(icicle);
274         mAirplaneModeEnabler = new AirplaneModeEnabler(getContext(), this);
275 
276         // TODO(b/37429702): Add animations and preference comparator back after initial screen is
277         // loaded (ODR).
278         setAnimationAllowed(false);
279 
280         addPreferences();
281 
282         mIsRestricted = isUiRestricted();
283     }
284 
addPreferences()285     private void addPreferences() {
286         addPreferencesFromResource(R.xml.network_provider_settings);
287 
288         mAirplaneModeMsgPreference = findPreference(PREF_KEY_AIRPLANE_MODE_MSG);
289         updateAirplaneModeMsgPreference(mAirplaneModeEnabler.isAirplaneModeOn() /* visible */);
290         mConnectedWifiEntryPreferenceCategory = findPreference(PREF_KEY_CONNECTED_ACCESS_POINTS);
291         mFirstWifiEntryPreferenceCategory = findPreference(PREF_KEY_FIRST_ACCESS_POINTS);
292         mWifiEntryPreferenceCategory = findPreference(PREF_KEY_ACCESS_POINTS);
293         mConfigureWifiSettingsPreference = findPreference(PREF_KEY_CONFIGURE_WIFI_SETTINGS);
294         mSavedNetworksPreference = findPreference(PREF_KEY_SAVED_NETWORKS);
295         mAddWifiNetworkPreference = new AddWifiNetworkPreference(getPrefContext());
296         mDataUsagePreference = findPreference(PREF_KEY_DATA_USAGE);
297         mDataUsagePreference.setVisible(DataUsageUtils.hasWifiRadio(getContext()));
298         mDataUsagePreference.setTemplate(
299                 NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL,
300                 null /* subscriberId */), 0 /*subId*/, null /*service*/);
301         mResetInternetPreference = findPreference(PREF_KEY_RESET_INTERNET);
302         if (mResetInternetPreference != null) {
303             mResetInternetPreference.setVisible(false);
304         }
305         addNetworkMobileProviderController();
306         addConnectedEthernetNetworkController();
307         addWifiSwitchPreferenceController();
308     }
309 
updateAirplaneModeMsgPreference(boolean visible)310     private void updateAirplaneModeMsgPreference(boolean visible) {
311         if (mAirplaneModeMsgPreference != null) {
312             mAirplaneModeMsgPreference.setVisible(visible);
313         }
314     }
315 
addNetworkMobileProviderController()316     private void addNetworkMobileProviderController() {
317         if (mNetworkMobileProviderController == null) {
318             mNetworkMobileProviderController = new NetworkMobileProviderController(
319                     getContext(), PREF_KEY_PROVIDER_MOBILE_NETWORK);
320         }
321         mNetworkMobileProviderController.init(getSettingsLifecycle());
322         mNetworkMobileProviderController.displayPreference(getPreferenceScreen());
323     }
324 
addConnectedEthernetNetworkController()325     private void addConnectedEthernetNetworkController() {
326         if (mConnectedEthernetNetworkController == null) {
327             mConnectedEthernetNetworkController =
328                     new ConnectedEthernetNetworkController(getContext(), getSettingsLifecycle());
329         }
330         mConnectedEthernetNetworkController.displayPreference(getPreferenceScreen());
331     }
332 
addWifiSwitchPreferenceController()333     private void addWifiSwitchPreferenceController() {
334         if (mWifiSwitchPreferenceController == null) {
335             mWifiSwitchPreferenceController =
336                     new WifiSwitchPreferenceController(getContext(), getSettingsLifecycle());
337         }
338         mWifiSwitchPreferenceController.displayPreference(getPreferenceScreen());
339     }
340 
341     @Override
onActivityCreated(Bundle savedInstanceState)342     public void onActivityCreated(Bundle savedInstanceState) {
343         super.onActivityCreated(savedInstanceState);
344 
345         mWifiPickerTrackerHelper =
346                 new WifiPickerTrackerHelper(getSettingsLifecycle(), getContext(), this);
347         mWifiPickerTracker = mWifiPickerTrackerHelper.getWifiPickerTracker();
348         mInternetUpdater = new InternetUpdater(getContext(), getSettingsLifecycle(), this);
349 
350         mConnectListener = new WifiConnectListener(getActivity());
351 
352         mSaveListener = new WifiManager.ActionListener() {
353             @Override
354             public void onSuccess() {
355             }
356 
357             @Override
358             public void onFailure(int reason) {
359                 Activity activity = getActivity();
360                 if (activity != null) {
361                     Toast.makeText(activity,
362                             R.string.wifi_failed_save_message,
363                             Toast.LENGTH_SHORT).show();
364                 }
365             }
366         };
367 
368         mForgetListener = new WifiManager.ActionListener() {
369             @Override
370             public void onSuccess() {
371             }
372 
373             @Override
374             public void onFailure(int reason) {
375                 Activity activity = getActivity();
376                 if (activity != null) {
377                     Toast.makeText(activity,
378                             R.string.wifi_failed_forget_message,
379                             Toast.LENGTH_SHORT).show();
380                 }
381             }
382         };
383         setHasOptionsMenu(true);
384 
385         if (savedInstanceState != null) {
386             mDialogMode = savedInstanceState.getInt(SAVE_DIALOG_MODE);
387             mDialogWifiEntryKey = savedInstanceState.getString(SAVE_DIALOG_WIFIENTRY_KEY);
388         }
389 
390         // If we're supposed to enable/disable the Next button based on our current connection
391         // state, start it off in the right state.
392         final Intent intent = getActivity().getIntent();
393         mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false);
394 
395         if (intent.hasExtra(EXTRA_START_CONNECT_SSID)) {
396             mOpenSsid = intent.getStringExtra(EXTRA_START_CONNECT_SSID);
397         }
398 
399         if (mNetworkMobileProviderController != null) {
400             mNetworkMobileProviderController.setWifiPickerTrackerHelper(mWifiPickerTrackerHelper);
401         }
402     }
403 
404     @Override
onAttach(Context context)405     public void onAttach(Context context) {
406         super.onAttach(context);
407 
408     }
409 
410     @Override
onStart()411     public void onStart() {
412         super.onStart();
413         if (mIsRestricted) {
414             restrictUi();
415             return;
416         }
417         mAirplaneModeEnabler.start();
418     }
419 
restrictUi()420     private void restrictUi() {
421         if (!isUiRestrictedByOnlyAdmin()) {
422             getEmptyTextView().setText(R.string.wifi_empty_list_user_restricted);
423         }
424         getPreferenceScreen().removeAll();
425     }
426 
427     @Override
onResume()428     public void onResume() {
429         super.onResume();
430 
431         // Disable the animation of the preference list
432         final RecyclerView prefListView = getListView();
433         if (prefListView != null) {
434             prefListView.setItemAnimator(null);
435         }
436 
437         // Because RestrictedSettingsFragment's onResume potentially requests authorization,
438         // which changes the restriction state, recalculate it.
439         final boolean alreadyImmutablyRestricted = mIsRestricted;
440         mIsRestricted = isUiRestricted();
441         if (!alreadyImmutablyRestricted && mIsRestricted) {
442             restrictUi();
443         }
444 
445         changeNextButtonState(mWifiPickerTracker.getConnectedWifiEntry() != null);
446     }
447 
448     @Override
onStop()449     public void onStop() {
450         mIsWifiEntryListStale = true;
451         getView().removeCallbacks(mRemoveLoadingRunnable);
452         getView().removeCallbacks(mUpdateWifiEntryPreferencesRunnable);
453         getView().removeCallbacks(mHideProgressBarRunnable);
454         mAirplaneModeEnabler.stop();
455         super.onStop();
456     }
457 
458     @Override
onDestroy()459     public void onDestroy() {
460         mAirplaneModeEnabler.close();
461         super.onDestroy();
462     }
463 
464     @Override
onActivityResult(int requestCode, int resultCode, Intent data)465     public void onActivityResult(int requestCode, int resultCode, Intent data) {
466         super.onActivityResult(requestCode, resultCode, data);
467 
468         if (requestCode == ADD_NETWORK_REQUEST) {
469             handleAddNetworkRequest(resultCode, data);
470             return;
471         } else if (requestCode == REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER) {
472             if (resultCode == Activity.RESULT_OK) {
473                 if (mDialog != null) {
474                     mDialog.dismiss();
475                 }
476             }
477             return;
478         } else if (requestCode == CONFIG_NETWORK_REQUEST) {
479             if (resultCode == Activity.RESULT_OK) {
480                 final WifiConfiguration wifiConfiguration = data.getParcelableExtra(
481                         ConfigureWifiEntryFragment.NETWORK_CONFIG_KEY);
482                 if (wifiConfiguration != null) {
483                     mWifiManager.connect(wifiConfiguration,
484                             new WifiConnectActionListener());
485                 }
486             }
487             return;
488         } else if (requestCode == MANAGE_SUBSCRIPTION) {
489             //Do nothing
490             return;
491         }
492 
493         final boolean formerlyRestricted = mIsRestricted;
494         mIsRestricted = isUiRestricted();
495         if (formerlyRestricted && !mIsRestricted
496                 && getPreferenceScreen().getPreferenceCount() == 0) {
497             // De-restrict the ui
498             addPreferences();
499         }
500     }
501 
502     @Override
onCreateAdapter(PreferenceScreen preferenceScreen)503     protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
504         final RecyclerView.Adapter adapter = super.onCreateAdapter(preferenceScreen);
505         adapter.setHasStableIds(true);
506         return adapter;
507     }
508 
509     @Override
getMetricsCategory()510     public int getMetricsCategory() {
511         return SettingsEnums.WIFI;
512     }
513 
514     @Override
onSaveInstanceState(Bundle outState)515     public void onSaveInstanceState(Bundle outState) {
516         super.onSaveInstanceState(outState);
517         // If dialog has been shown, save its state.
518         if (mDialog != null) {
519             outState.putInt(SAVE_DIALOG_MODE, mDialogMode);
520             outState.putString(SAVE_DIALOG_WIFIENTRY_KEY, mDialogWifiEntryKey);
521         }
522     }
523 
524     @Override
onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info)525     public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
526         Preference preference = (Preference) view.getTag();
527         if (!(preference instanceof LongPressWifiEntryPreference)) {
528             // Do nothing.
529             return;
530         }
531 
532         // Cache the WifiEntry for onContextItemSelected. Don't use it in other methods.
533         mSelectedWifiEntry = ((LongPressWifiEntryPreference) preference).getWifiEntry();
534 
535         menu.setHeaderTitle(mSelectedWifiEntry.getTitle());
536         if (mSelectedWifiEntry.canConnect()) {
537             menu.add(Menu.NONE, MENU_ID_CONNECT, 0 /* order */, R.string.wifi_connect);
538         }
539 
540         if (mSelectedWifiEntry.canDisconnect()) {
541             menu.add(Menu.NONE, MENU_ID_SHARE, 0 /* order */, R.string.share);
542             menu.add(Menu.NONE, MENU_ID_DISCONNECT, 1 /* order */,
543                     R.string.wifi_disconnect_button_text);
544         }
545 
546         // "forget" for normal saved network. And "disconnect" for ephemeral network because it
547         // could only be disconnected and be put in blocklists so it won't be used again.
548         if (canForgetNetwork()) {
549             menu.add(Menu.NONE, MENU_ID_FORGET, 0 /* order */, R.string.forget);
550         }
551 
552         WifiConfiguration config = mSelectedWifiEntry.getWifiConfiguration();
553         // Some configs are ineditable
554         if (WifiUtils.isNetworkLockedDown(getActivity(), config)) {
555             return;
556         }
557 
558         if (mSelectedWifiEntry.isSaved() && mSelectedWifiEntry.getConnectedState()
559                 != WifiEntry.CONNECTED_STATE_CONNECTED) {
560             menu.add(Menu.NONE, MENU_ID_MODIFY, 0 /* order */, R.string.wifi_modify);
561         }
562     }
563 
canForgetNetwork()564     private boolean canForgetNetwork() {
565         return mSelectedWifiEntry.canForget() && !WifiUtils.isNetworkLockedDown(getActivity(),
566                 mSelectedWifiEntry.getWifiConfiguration());
567     }
568 
569     @Override
onContextItemSelected(MenuItem item)570     public boolean onContextItemSelected(MenuItem item) {
571         switch (item.getItemId()) {
572             case MENU_ID_CONNECT:
573                 connect(mSelectedWifiEntry, true /* editIfNoConfig */, false /* fullScreenEdit */);
574                 return true;
575             case MENU_ID_DISCONNECT:
576                 mSelectedWifiEntry.disconnect(null /* callback */);
577                 return true;
578             case MENU_ID_FORGET:
579                 forget(mSelectedWifiEntry);
580                 return true;
581             case MENU_ID_SHARE:
582                 WifiDppUtils.showLockScreen(getContext(),
583                         () -> launchWifiDppConfiguratorActivity(mSelectedWifiEntry));
584                 return true;
585             case MENU_ID_MODIFY:
586                 showDialog(mSelectedWifiEntry, WifiConfigUiBase2.MODE_MODIFY);
587                 return true;
588             default:
589                 return super.onContextItemSelected(item);
590         }
591     }
592 
593     @Override
onPreferenceTreeClick(Preference preference)594     public boolean onPreferenceTreeClick(Preference preference) {
595         // If the preference has a fragment set, open that
596         if (preference.getFragment() != null) {
597             preference.setOnPreferenceClickListener(null);
598             return super.onPreferenceTreeClick(preference);
599         }
600 
601         if (preference instanceof LongPressWifiEntryPreference) {
602             final WifiEntry selectedEntry =
603                     ((LongPressWifiEntryPreference) preference).getWifiEntry();
604 
605             if (selectedEntry.shouldEditBeforeConnect()) {
606                 launchConfigNewNetworkFragment(selectedEntry);
607                 return true;
608             }
609 
610             connect(selectedEntry, true /* editIfNoConfig */, true /* fullScreenEdit */);
611         } else if (preference == mAddWifiNetworkPreference) {
612             onAddNetworkPressed();
613         } else {
614             return super.onPreferenceTreeClick(preference);
615         }
616         return true;
617     }
618 
launchWifiDppConfiguratorActivity(WifiEntry wifiEntry)619     private void launchWifiDppConfiguratorActivity(WifiEntry wifiEntry) {
620         final Intent intent = WifiDppUtils.getConfiguratorQrCodeGeneratorIntentOrNull(getContext(),
621                 mWifiManager, wifiEntry);
622 
623         if (intent == null) {
624             Log.e(TAG, "Launch Wi-Fi DPP QR code generator with a wrong Wi-Fi network!");
625         } else {
626             mMetricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN,
627                     SettingsEnums.ACTION_SETTINGS_SHARE_WIFI_QR_CODE,
628                     SettingsEnums.SETTINGS_WIFI_DPP_CONFIGURATOR,
629                     /* key */ null,
630                     /* value */ Integer.MIN_VALUE);
631 
632             startActivity(intent);
633         }
634     }
635 
showDialog(WifiEntry wifiEntry, int dialogMode)636     private void showDialog(WifiEntry wifiEntry, int dialogMode) {
637         if (WifiUtils.isNetworkLockedDown(getActivity(), wifiEntry.getWifiConfiguration())
638                 && wifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) {
639             RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(),
640                     RestrictedLockUtilsInternal.getDeviceOwner(getActivity()));
641             return;
642         }
643 
644         if (mDialog != null) {
645             removeDialog(WIFI_DIALOG_ID);
646             mDialog = null;
647         }
648 
649         // Save the access point and edit mode
650         mDialogWifiEntry = wifiEntry;
651         mDialogWifiEntryKey = wifiEntry.getKey();
652         mDialogMode = dialogMode;
653 
654         showDialog(WIFI_DIALOG_ID);
655     }
656 
657     @Override
onCreateDialog(int dialogId)658     public Dialog onCreateDialog(int dialogId) {
659         switch (dialogId) {
660             case WIFI_DIALOG_ID:
661                 // modify network
662                 mDialog = WifiDialog2
663                         .createModal(getActivity(), this, mDialogWifiEntry, mDialogMode);
664                 return mDialog;
665             default:
666                 return super.onCreateDialog(dialogId);
667         }
668     }
669 
670     @Override
onDialogShowing()671     public void onDialogShowing() {
672         super.onDialogShowing();
673         setOnDismissListener(this);
674     }
675 
676     @Override
onDismiss(DialogInterface dialog)677     public void onDismiss(DialogInterface dialog) {
678         // We don't keep any dialog object when dialog was dismissed.
679         mDialog = null;
680         mDialogWifiEntry = null;
681         mDialogWifiEntryKey = null;
682     }
683 
684     @Override
getDialogMetricsCategory(int dialogId)685     public int getDialogMetricsCategory(int dialogId) {
686         switch (dialogId) {
687             case WIFI_DIALOG_ID:
688                 return SettingsEnums.DIALOG_WIFI_AP_EDIT;
689             default:
690                 return 0;
691         }
692     }
693 
694     @Override
onInternetTypeChanged(@nternetUpdater.InternetType int internetType)695     public void onInternetTypeChanged(@InternetUpdater.InternetType int internetType) {
696         ThreadUtils.postOnMainThread(() -> {
697             onWifiStateChanged();
698         });
699     }
700 
701     /** Called when the state of Wifi has changed. */
702     @Override
onWifiStateChanged()703     public void onWifiStateChanged() {
704         if (mIsRestricted) {
705             return;
706         }
707         final int wifiState = mWifiPickerTracker.getWifiState();
708 
709         if (isVerboseLoggingEnabled()) {
710             Log.i(TAG, "onWifiStateChanged called with wifi state: " + wifiState);
711         }
712 
713         switch (wifiState) {
714             case WifiManager.WIFI_STATE_ENABLED:
715                 updateWifiEntryPreferences();
716                 break;
717 
718             case WifiManager.WIFI_STATE_ENABLING:
719                 removeConnectedWifiEntryPreference();
720                 removeWifiEntryPreference();
721                 setProgressBarVisible(true);
722                 break;
723 
724             case WifiManager.WIFI_STATE_DISABLING:
725                 removeConnectedWifiEntryPreference();
726                 removeWifiEntryPreference();
727                 break;
728 
729             case WifiManager.WIFI_STATE_DISABLED:
730                 removeConnectedWifiEntryPreference();
731                 removeWifiEntryPreference();
732                 setAdditionalSettingsSummaries();
733                 setProgressBarVisible(false);
734                 mClickedConnect = false;
735                 break;
736         }
737     }
738 
739     @Override
onWifiEntriesChanged()740     public void onWifiEntriesChanged() {
741         if (mIsWifiEntryListStale) {
742             mIsWifiEntryListStale = false;
743             updateWifiEntryPreferences();
744         } else {
745             updateWifiEntryPreferencesDelayed();
746         }
747         changeNextButtonState(mWifiPickerTracker.getConnectedWifiEntry() != null);
748 
749         // Edit the Wi-Fi network of specified SSID.
750         if (mOpenSsid != null) {
751             Optional<WifiEntry> matchedWifiEntry = mWifiPickerTracker.getWifiEntries().stream()
752                     .filter(wifiEntry -> TextUtils.equals(mOpenSsid, wifiEntry.getSsid()))
753                     .filter(wifiEntry -> wifiEntry.getSecurity() != WifiEntry.SECURITY_NONE
754                             && wifiEntry.getSecurity() != WifiEntry.SECURITY_OWE)
755                     .filter(wifiEntry -> !wifiEntry.isSaved()
756                             || isDisabledByWrongPassword(wifiEntry))
757                     .findFirst();
758             if (matchedWifiEntry.isPresent()) {
759                 mOpenSsid = null;
760                 launchConfigNewNetworkFragment(matchedWifiEntry.get());
761             }
762         }
763     }
764 
765     @Override
onNumSavedNetworksChanged()766     public void onNumSavedNetworksChanged() {
767         if (isFinishingOrDestroyed()) {
768             return;
769         }
770         setAdditionalSettingsSummaries();
771     }
772 
773     @Override
onNumSavedSubscriptionsChanged()774     public void onNumSavedSubscriptionsChanged() {
775         if (isFinishingOrDestroyed()) {
776             return;
777         }
778         setAdditionalSettingsSummaries();
779     }
780 
781     /**
782      * Updates WifiEntries from {@link WifiPickerTracker#getWifiEntries()}. Adds a delay to have
783      * progress bar displayed before starting to modify entries.
784      */
updateWifiEntryPreferencesDelayed()785     private void updateWifiEntryPreferencesDelayed() {
786         // Safeguard from some delayed event handling
787         if (getActivity() != null && !mIsRestricted
788                 && mWifiPickerTracker.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
789             final View view = getView();
790             final Handler handler = view.getHandler();
791             if (handler != null && handler.hasCallbacks(mUpdateWifiEntryPreferencesRunnable)) {
792                 return;
793             }
794             setProgressBarVisible(true);
795             view.postDelayed(mUpdateWifiEntryPreferencesRunnable, 300);
796         }
797     }
798 
updateWifiEntryPreferences()799     protected void updateWifiEntryPreferences() {
800         // bypass the update if the activity and the view are not ready, or it's restricted UI.
801         if (getActivity() == null || getView() == null || mIsRestricted) {
802             return;
803         }
804         // in case state has changed
805         if (mWifiPickerTracker.getWifiState() != WifiManager.WIFI_STATE_ENABLED) {
806             return;
807         }
808 
809         boolean hasAvailableWifiEntries = false;
810         mWifiEntryPreferenceCategory.setVisible(true);
811 
812         final WifiEntry connectedEntry = mWifiPickerTracker.getConnectedWifiEntry();
813         PreferenceCategory connectedWifiPreferenceCategory = getConnectedWifiPreferenceCategory();
814         connectedWifiPreferenceCategory.setVisible(connectedEntry != null);
815         if (connectedEntry != null) {
816             final LongPressWifiEntryPreference connectedPref =
817                     connectedWifiPreferenceCategory.findPreference(connectedEntry.getKey());
818             if (connectedPref == null || connectedPref.getWifiEntry() != connectedEntry) {
819                 connectedWifiPreferenceCategory.removeAll();
820                 final ConnectedWifiEntryPreference pref =
821                         createConnectedWifiEntryPreference(connectedEntry);
822                 pref.setKey(connectedEntry.getKey());
823                 pref.refresh();
824                 connectedWifiPreferenceCategory.addPreference(pref);
825                 pref.setOnPreferenceClickListener(preference -> {
826                     if (connectedEntry.canSignIn()) {
827                         connectedEntry.signIn(null /* callback */);
828                     } else {
829                         launchNetworkDetailsFragment(pref);
830                     }
831                     return true;
832                 });
833                 pref.setOnGearClickListener(preference -> {
834                     launchNetworkDetailsFragment(pref);
835                 });
836 
837                 if (mClickedConnect) {
838                     mClickedConnect = false;
839                     scrollToPreference(connectedWifiPreferenceCategory);
840                 }
841             }
842         } else {
843             connectedWifiPreferenceCategory.removeAll();
844         }
845 
846         int index = 0;
847         cacheRemoveAllPrefs(mWifiEntryPreferenceCategory);
848         List<WifiEntry> wifiEntries = mWifiPickerTracker.getWifiEntries();
849         for (WifiEntry wifiEntry : wifiEntries) {
850             hasAvailableWifiEntries = true;
851 
852             String key = wifiEntry.getKey();
853             LongPressWifiEntryPreference pref =
854                     (LongPressWifiEntryPreference) getCachedPreference(key);
855             if (pref != null) {
856                 if (pref.getWifiEntry() == wifiEntry) {
857                     pref.setOrder(index++);
858                     continue;
859                 } else {
860                     // Create a new preference if the underlying WifiEntry object has changed
861                     removePreference(key);
862                 }
863             }
864 
865             pref = createLongPressWifiEntryPreference(wifiEntry);
866             pref.setKey(wifiEntry.getKey());
867             pref.setOrder(index++);
868             pref.refresh();
869 
870             if (wifiEntry.getHelpUriString() != null) {
871                 pref.setOnButtonClickListener(preference -> {
872                     openSubscriptionHelpPage(wifiEntry);
873                 });
874             }
875             mWifiEntryPreferenceCategory.addPreference(pref);
876         }
877         removeCachedPrefs(mWifiEntryPreferenceCategory);
878 
879         if (!hasAvailableWifiEntries) {
880             setProgressBarVisible(true);
881             Preference pref = new Preference(getPrefContext());
882             pref.setSelectable(false);
883             pref.setSummary(R.string.wifi_empty_list_wifi_on);
884             pref.setOrder(index++);
885             pref.setKey(PREF_KEY_EMPTY_WIFI_LIST);
886             mWifiEntryPreferenceCategory.addPreference(pref);
887         } else {
888             // Continuing showing progress bar for an additional delay to overlap with animation
889             getView().postDelayed(mHideProgressBarRunnable, 1700 /* delay millis */);
890         }
891 
892         mAddWifiNetworkPreference.setOrder(index++);
893         mWifiEntryPreferenceCategory.addPreference(mAddWifiNetworkPreference);
894         setAdditionalSettingsSummaries();
895     }
896 
897     @VisibleForTesting
getConnectedWifiPreferenceCategory()898     PreferenceCategory getConnectedWifiPreferenceCategory() {
899         if (mInternetUpdater.getInternetType() == InternetUpdater.INTERNET_WIFI) {
900             mFirstWifiEntryPreferenceCategory.setVisible(false);
901             mFirstWifiEntryPreferenceCategory.removeAll();
902             return mConnectedWifiEntryPreferenceCategory;
903         }
904 
905         mConnectedWifiEntryPreferenceCategory.setVisible(false);
906         mConnectedWifiEntryPreferenceCategory.removeAll();
907         return mFirstWifiEntryPreferenceCategory;
908     }
909 
910     @VisibleForTesting
createConnectedWifiEntryPreference(WifiEntry wifiEntry)911     ConnectedWifiEntryPreference createConnectedWifiEntryPreference(WifiEntry wifiEntry) {
912         if (mInternetUpdater.getInternetType() == InternetUpdater.INTERNET_WIFI) {
913             return new ConnectedWifiEntryPreference(getPrefContext(), wifiEntry, this);
914         }
915         return new FirstWifiEntryPreference(getPrefContext(), wifiEntry, this);
916     }
917 
launchNetworkDetailsFragment(LongPressWifiEntryPreference pref)918     private void launchNetworkDetailsFragment(LongPressWifiEntryPreference pref) {
919         final WifiEntry wifiEntry = pref.getWifiEntry();
920         final Context context = getContext();
921         final CharSequence title =
922                 FeatureFlagUtils.isEnabled(context, FeatureFlags.WIFI_DETAILS_DATAUSAGE_HEADER)
923                         ? wifiEntry.getTitle()
924                         : context.getText(R.string.pref_title_network_details);
925 
926         final Bundle bundle = new Bundle();
927         bundle.putString(WifiNetworkDetailsFragment2.KEY_CHOSEN_WIFIENTRY_KEY, wifiEntry.getKey());
928 
929         new SubSettingLauncher(context)
930                 .setTitleText(title)
931                 .setDestination(WifiNetworkDetailsFragment2.class.getName())
932                 .setArguments(bundle)
933                 .setSourceMetricsCategory(getMetricsCategory())
934                 .launch();
935     }
936 
937     @VisibleForTesting
createLongPressWifiEntryPreference(WifiEntry wifiEntry)938     LongPressWifiEntryPreference createLongPressWifiEntryPreference(WifiEntry wifiEntry) {
939         return new LongPressWifiEntryPreference(getPrefContext(), wifiEntry, this);
940     }
941 
launchAddNetworkFragment()942     private void launchAddNetworkFragment() {
943         new SubSettingLauncher(getContext())
944                 .setTitleRes(R.string.wifi_add_network)
945                 .setDestination(AddNetworkFragment.class.getName())
946                 .setSourceMetricsCategory(getMetricsCategory())
947                 .setResultListener(this, ADD_NETWORK_REQUEST)
948                 .launch();
949     }
950 
951     /** Removes all preferences and hide the {@link #mConnectedWifiEntryPreferenceCategory}. */
removeConnectedWifiEntryPreference()952     private void removeConnectedWifiEntryPreference() {
953         mConnectedWifiEntryPreferenceCategory.removeAll();
954         mConnectedWifiEntryPreferenceCategory.setVisible(false);
955     }
956 
removeWifiEntryPreference()957     private void removeWifiEntryPreference() {
958         mWifiEntryPreferenceCategory.removeAll();
959         mWifiEntryPreferenceCategory.setVisible(false);
960     }
961 
962     @VisibleForTesting
setAdditionalSettingsSummaries()963     void setAdditionalSettingsSummaries() {
964         if (!FeatureFlagUtils.isEnabled(getContext(), FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) {
965             mConfigureWifiSettingsPreference.setSummary(getString(
966                     isWifiWakeupEnabled()
967                             ? R.string.wifi_configure_settings_preference_summary_wakeup_on
968                             : R.string.wifi_configure_settings_preference_summary_wakeup_off));
969         }
970 
971         final int numSavedNetworks = mWifiPickerTracker.getNumSavedNetworks();
972         final int numSavedSubscriptions = mWifiPickerTracker.getNumSavedSubscriptions();
973         if (numSavedNetworks + numSavedSubscriptions > 0) {
974             mSavedNetworksPreference.setVisible(true);
975             mSavedNetworksPreference.setSummary(
976                     getSavedNetworkSettingsSummaryText(numSavedNetworks, numSavedSubscriptions));
977         } else {
978             mSavedNetworksPreference.setVisible(false);
979         }
980     }
981 
getSavedNetworkSettingsSummaryText( int numSavedNetworks, int numSavedSubscriptions)982     private String getSavedNetworkSettingsSummaryText(
983             int numSavedNetworks, int numSavedSubscriptions) {
984         if (numSavedSubscriptions == 0) {
985             return getResources().getQuantityString(R.plurals.wifi_saved_access_points_summary,
986                     numSavedNetworks, numSavedNetworks);
987         } else if (numSavedNetworks == 0) {
988             return getResources().getQuantityString(
989                     R.plurals.wifi_saved_passpoint_access_points_summary,
990                     numSavedSubscriptions, numSavedSubscriptions);
991         } else {
992             final int numTotalEntries = numSavedNetworks + numSavedSubscriptions;
993             return getResources().getQuantityString(R.plurals.wifi_saved_all_access_points_summary,
994                     numTotalEntries, numTotalEntries);
995         }
996     }
997 
isWifiWakeupEnabled()998     private boolean isWifiWakeupEnabled() {
999         final Context context = getContext();
1000         final PowerManager powerManager = context.getSystemService(PowerManager.class);
1001         final ContentResolver contentResolver = context.getContentResolver();
1002         return mWifiManager.isAutoWakeupEnabled()
1003                 && mWifiManager.isScanAlwaysAvailable()
1004                 && Settings.Global.getInt(contentResolver,
1005                 Settings.Global.AIRPLANE_MODE_ON, 0) == 0
1006                 && !powerManager.isPowerSaveMode();
1007     }
1008 
setProgressBarVisible(boolean visible)1009     protected void setProgressBarVisible(boolean visible) {
1010         showPinnedHeader(visible);
1011     }
1012 
1013     @VisibleForTesting
handleAddNetworkRequest(int result, Intent data)1014     void handleAddNetworkRequest(int result, Intent data) {
1015         if (result == Activity.RESULT_OK) {
1016             handleAddNetworkSubmitEvent(data);
1017         }
1018     }
1019 
handleAddNetworkSubmitEvent(Intent data)1020     private void handleAddNetworkSubmitEvent(Intent data) {
1021         final WifiConfiguration wifiConfiguration = data.getParcelableExtra(
1022                 AddNetworkFragment.WIFI_CONFIG_KEY);
1023         if (wifiConfiguration != null) {
1024             mWifiManager.save(wifiConfiguration, mSaveListener);
1025         }
1026     }
1027 
1028     /**
1029      * Called when "add network" button is pressed.
1030      */
onAddNetworkPressed()1031     private void onAddNetworkPressed() {
1032         launchAddNetworkFragment();
1033     }
1034 
1035     @Override
getHelpResource()1036     public int getHelpResource() {
1037         return R.string.help_url_wifi;
1038     }
1039 
1040     /**
1041      * Renames/replaces "Next" button when appropriate. "Next" button usually exists in
1042      * Wi-Fi setup screens, not in usual wifi settings screen.
1043      *
1044      * @param enabled true when the device is connected to a wifi network.
1045      */
1046     @VisibleForTesting
changeNextButtonState(boolean enabled)1047     void changeNextButtonState(boolean enabled) {
1048         if (mEnableNextOnConnection && hasNextButton()) {
1049             getNextButton().setEnabled(enabled);
1050         }
1051     }
1052 
1053     @Override
onForget(WifiDialog2 dialog)1054     public void onForget(WifiDialog2 dialog) {
1055         forget(dialog.getWifiEntry());
1056     }
1057 
1058     @Override
onSubmit(WifiDialog2 dialog)1059     public void onSubmit(WifiDialog2 dialog) {
1060         final int dialogMode = dialog.getMode();
1061         final WifiConfiguration config = dialog.getController().getConfig();
1062         final WifiEntry wifiEntry = dialog.getWifiEntry();
1063 
1064         if (dialogMode == WifiConfigUiBase2.MODE_MODIFY) {
1065             if (config == null) {
1066                 Toast.makeText(getContext(), R.string.wifi_failed_save_message,
1067                         Toast.LENGTH_SHORT).show();
1068             } else {
1069                 mWifiManager.save(config, mSaveListener);
1070             }
1071         } else if (dialogMode == WifiConfigUiBase2.MODE_CONNECT
1072                 || (dialogMode == WifiConfigUiBase2.MODE_VIEW && wifiEntry.canConnect())) {
1073             if (config == null) {
1074                 connect(wifiEntry, false /* editIfNoConfig */,
1075                         false /* fullScreenEdit*/);
1076             } else {
1077                 mWifiManager.connect(config, new WifiConnectActionListener());
1078             }
1079         }
1080     }
1081 
1082     @Override
onScan(WifiDialog2 dialog, String ssid)1083     public void onScan(WifiDialog2 dialog, String ssid) {
1084         // Launch QR code scanner to join a network.
1085         startActivityForResult(WifiDppUtils.getEnrolleeQrCodeScannerIntent(ssid),
1086                 REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER);
1087     }
1088 
forget(WifiEntry wifiEntry)1089     private void forget(WifiEntry wifiEntry) {
1090         mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_WIFI_FORGET);
1091         wifiEntry.forget(null /* callback */);
1092     }
1093 
1094     @VisibleForTesting
connect(WifiEntry wifiEntry, boolean editIfNoConfig, boolean fullScreenEdit)1095     void connect(WifiEntry wifiEntry, boolean editIfNoConfig, boolean fullScreenEdit) {
1096         mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_WIFI_CONNECT,
1097                 wifiEntry.isSaved());
1098 
1099         // If it's an unsaved secure WifiEntry, it will callback
1100         // ConnectCallback#onConnectResult with ConnectCallback#CONNECT_STATUS_FAILURE_NO_CONFIG
1101         wifiEntry.connect(new WifiEntryConnectCallback(wifiEntry, editIfNoConfig,
1102                 fullScreenEdit));
1103     }
1104 
1105     private class WifiConnectActionListener implements WifiManager.ActionListener {
1106         @Override
onSuccess()1107         public void onSuccess() {
1108             mClickedConnect = true;
1109         }
1110 
1111         @Override
onFailure(int reason)1112         public void onFailure(int reason) {
1113             if (isFinishingOrDestroyed()) {
1114                 return;
1115             }
1116             Toast.makeText(getContext(), R.string.wifi_failed_connect_message, Toast.LENGTH_SHORT)
1117                     .show();
1118         }
1119     };
1120 
1121     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
1122             new BaseSearchIndexProvider(R.xml.network_provider_settings) {
1123                 @Override
1124                 public List<String> getNonIndexableKeys(Context context) {
1125                     final List<String> keys = super.getNonIndexableKeys(context);
1126 
1127                     final WifiManager wifiManager = context.getSystemService(WifiManager.class);
1128                     if (WifiSavedConfigUtils.getAllConfigsCount(context, wifiManager) == 0) {
1129                         keys.add(PREF_KEY_SAVED_NETWORKS);
1130                     }
1131 
1132                     if (!DataUsageUtils.hasWifiRadio(context)) {
1133                         keys.add(PREF_KEY_DATA_USAGE);
1134                     }
1135                     return keys;
1136                 }
1137             };
1138 
1139     private class WifiEntryConnectCallback implements ConnectCallback {
1140         final WifiEntry mConnectWifiEntry;
1141         final boolean mEditIfNoConfig;
1142         final boolean mFullScreenEdit;
1143 
WifiEntryConnectCallback(WifiEntry connectWifiEntry, boolean editIfNoConfig, boolean fullScreenEdit)1144         WifiEntryConnectCallback(WifiEntry connectWifiEntry, boolean editIfNoConfig,
1145                 boolean fullScreenEdit) {
1146             mConnectWifiEntry = connectWifiEntry;
1147             mEditIfNoConfig = editIfNoConfig;
1148             mFullScreenEdit = fullScreenEdit;
1149         }
1150 
1151         @Override
onConnectResult(@onnectStatus int status)1152         public void onConnectResult(@ConnectStatus int status) {
1153             if (isFinishingOrDestroyed()) {
1154                 return;
1155             }
1156 
1157             if (status == ConnectCallback.CONNECT_STATUS_SUCCESS) {
1158                 mClickedConnect = true;
1159             } else if (status == ConnectCallback.CONNECT_STATUS_FAILURE_NO_CONFIG) {
1160                 if (mEditIfNoConfig) {
1161                     // Edit an unsaved secure Wi-Fi network.
1162                     if (mFullScreenEdit) {
1163                         launchConfigNewNetworkFragment(mConnectWifiEntry);
1164                     } else {
1165                         showDialog(mConnectWifiEntry, WifiConfigUiBase2.MODE_CONNECT);
1166                     }
1167                 }
1168             } else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) {
1169                 Toast.makeText(getContext(), R.string.wifi_failed_connect_message,
1170                         Toast.LENGTH_SHORT).show();
1171             }
1172         }
1173     }
1174 
launchConfigNewNetworkFragment(WifiEntry wifiEntry)1175     private void launchConfigNewNetworkFragment(WifiEntry wifiEntry) {
1176         final Bundle bundle = new Bundle();
1177         bundle.putString(WifiNetworkDetailsFragment2.KEY_CHOSEN_WIFIENTRY_KEY,
1178                 wifiEntry.getKey());
1179         new SubSettingLauncher(getContext())
1180                 .setTitleText(wifiEntry.getTitle())
1181                 .setDestination(ConfigureWifiEntryFragment.class.getName())
1182                 .setArguments(bundle)
1183                 .setSourceMetricsCategory(getMetricsCategory())
1184                 .setResultListener(NetworkProviderSettings.this, CONFIG_NETWORK_REQUEST)
1185                 .launch();
1186     }
1187 
1188     /** Helper method to return whether a WifiEntry is disabled due to a wrong password */
isDisabledByWrongPassword(WifiEntry wifiEntry)1189     private static boolean isDisabledByWrongPassword(WifiEntry wifiEntry) {
1190         WifiConfiguration config = wifiEntry.getWifiConfiguration();
1191         if (config == null) {
1192             return false;
1193         }
1194         WifiConfiguration.NetworkSelectionStatus networkStatus =
1195                 config.getNetworkSelectionStatus();
1196         if (networkStatus == null
1197                 || networkStatus.getNetworkSelectionStatus() == NETWORK_SELECTION_ENABLED) {
1198             return false;
1199         }
1200         int reason = networkStatus.getNetworkSelectionDisableReason();
1201         return WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD == reason;
1202     }
1203 
1204     @VisibleForTesting
openSubscriptionHelpPage(WifiEntry wifiEntry)1205     void openSubscriptionHelpPage(WifiEntry wifiEntry) {
1206         final Intent intent = getHelpIntent(getContext(), wifiEntry.getHelpUriString());
1207         if (intent != null) {
1208             try {
1209                 startActivityForResult(intent, MANAGE_SUBSCRIPTION);
1210             } catch (ActivityNotFoundException e) {
1211                 Log.e(TAG, "Activity was not found for intent, " + intent.toString());
1212             }
1213         }
1214     }
1215 
1216     @VisibleForTesting
getHelpIntent(Context context, String helpUrlString)1217     Intent getHelpIntent(Context context, String helpUrlString) {
1218         return HelpUtils.getHelpIntent(context, helpUrlString, context.getClass().getName());
1219     }
1220 
1221     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)1222     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
1223         if (!mAirplaneModeEnabler.isAirplaneModeOn()) {
1224             MenuItem item = menu.add(0, MENU_FIX_CONNECTIVITY, 0, R.string.fix_connectivity);
1225             item.setIcon(R.drawable.ic_repair_24dp);
1226             item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
1227         }
1228         super.onCreateOptionsMenu(menu, inflater);
1229     }
1230 
1231     @Override
onOptionsItemSelected(MenuItem menuItem)1232     public boolean onOptionsItemSelected(MenuItem menuItem) {
1233         if (menuItem.getItemId() == MENU_FIX_CONNECTIVITY) {
1234             if (isPhoneOnCall()) {
1235                 showResetInternetDialog();
1236                 return true;
1237             }
1238             fixConnectivity();
1239             return true;
1240         }
1241         return super.onOptionsItemSelected(menuItem);
1242     }
1243 
1244     @VisibleForTesting
showResetInternetDialog()1245     void showResetInternetDialog() {
1246         AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
1247         DialogInterface.OnClickListener resetInternetClickListener =
1248                 new Dialog.OnClickListener() {
1249                     @Override
1250                     public void onClick(DialogInterface dialog, int which) {
1251                         fixConnectivity();
1252                     }
1253                 };
1254         builder.setTitle(R.string.reset_your_internet_title)
1255                 .setMessage(R.string.reset_internet_text)
1256                 .setPositiveButton(R.string.tts_reset, resetInternetClickListener)
1257                 .setNegativeButton(android.R.string.cancel, null)
1258                 .create()
1259                 .show();
1260     }
1261 
1262     @VisibleForTesting
isPhoneOnCall()1263     boolean isPhoneOnCall() {
1264         TelephonyManager mTelephonyManager = getActivity().getSystemService(TelephonyManager.class);
1265         int state = mTelephonyManager.getCallState();
1266         return state != TelephonyManager.CALL_STATE_IDLE;
1267     }
1268 
fixConnectivity()1269     private void fixConnectivity() {
1270         if (mInternetResetHelper == null) {
1271             mInternetResetHelper = new InternetResetHelper(getContext(), getLifecycle());
1272             mInternetResetHelper.setResettingPreference(mResetInternetPreference);
1273             mInternetResetHelper.setMobileNetworkController(mNetworkMobileProviderController);
1274             mInternetResetHelper.setWifiTogglePreference(
1275                     findPreference(WifiSwitchPreferenceController.KEY));
1276             mInternetResetHelper.addWifiNetworkPreference(mConnectedWifiEntryPreferenceCategory);
1277             mInternetResetHelper.addWifiNetworkPreference(mFirstWifiEntryPreferenceCategory);
1278             mInternetResetHelper.addWifiNetworkPreference(mWifiEntryPreferenceCategory);
1279         }
1280         mInternetResetHelper.restart();
1281     }
1282 
1283     /**
1284      * Called when airplane mode status is changed.
1285      *
1286      * @param isAirplaneModeOn The airplane mode is on
1287      */
1288     @Override
onAirplaneModeChanged(boolean isAirplaneModeOn)1289     public void onAirplaneModeChanged(boolean isAirplaneModeOn) {
1290         updateAirplaneModeMsgPreference(isAirplaneModeOn /* visible */);
1291     }
1292 
1293     /**
1294      * A Wi-Fi preference for the connected Wi-Fi network without internet access.
1295      *
1296      * Override the icon color attribute by {@link ConnectedWifiEntryPreference#getIconColorAttr()}
1297      * and show the icon color to android.R.attr.colorControlNormal for the preference.
1298      */
1299     public class FirstWifiEntryPreference extends ConnectedWifiEntryPreference {
FirstWifiEntryPreference(Context context, WifiEntry wifiEntry, Fragment fragment)1300         public FirstWifiEntryPreference(Context context, WifiEntry wifiEntry,
1301                 Fragment fragment) {
1302             super(context, wifiEntry, fragment);
1303         }
1304 
1305         @Override
getIconColorAttr()1306         protected int getIconColorAttr() {
1307             return android.R.attr.colorControlNormal;
1308         }
1309     }
1310 }
1311