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.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.HandlerThread;
36 import android.os.Looper;
37 import android.os.PowerManager;
38 import android.os.Process;
39 import android.os.SimpleClock;
40 import android.os.SystemClock;
41 import android.provider.Settings;
42 import android.text.TextUtils;
43 import android.util.FeatureFlagUtils;
44 import android.util.Log;
45 import android.view.ContextMenu;
46 import android.view.ContextMenu.ContextMenuInfo;
47 import android.view.Menu;
48 import android.view.MenuItem;
49 import android.view.View;
50 import android.widget.Toast;
51 
52 import androidx.annotation.VisibleForTesting;
53 import androidx.preference.Preference;
54 import androidx.preference.PreferenceCategory;
55 import androidx.preference.PreferenceScreen;
56 import androidx.recyclerview.widget.RecyclerView;
57 
58 import com.android.settings.LinkifyUtils;
59 import com.android.settings.R;
60 import com.android.settings.RestrictedSettingsFragment;
61 import com.android.settings.SettingsActivity;
62 import com.android.settings.Utils;
63 import com.android.settings.core.FeatureFlags;
64 import com.android.settings.core.SubSettingLauncher;
65 import com.android.settings.datausage.DataUsagePreference;
66 import com.android.settings.datausage.DataUsageUtils;
67 import com.android.settings.location.WifiScanningFragment;
68 import com.android.settings.overlay.FeatureFactory;
69 import com.android.settings.search.BaseSearchIndexProvider;
70 import com.android.settings.widget.MainSwitchBarController;
71 import com.android.settings.wifi.details.WifiNetworkDetailsFragment;
72 import com.android.settings.wifi.dpp.WifiDppUtils;
73 import com.android.settingslib.HelpUtils;
74 import com.android.settingslib.RestrictedLockUtils;
75 import com.android.settingslib.RestrictedLockUtilsInternal;
76 import com.android.settingslib.search.Indexable;
77 import com.android.settingslib.search.SearchIndexable;
78 import com.android.settingslib.wifi.LongPressWifiEntryPreference;
79 import com.android.settingslib.wifi.WifiSavedConfigUtils;
80 import com.android.wifitrackerlib.WifiEntry;
81 import com.android.wifitrackerlib.WifiEntry.ConnectCallback;
82 import com.android.wifitrackerlib.WifiPickerTracker;
83 
84 import java.time.Clock;
85 import java.time.ZoneOffset;
86 import java.util.List;
87 import java.util.Optional;
88 
89 /**
90  * UI for Wi-Fi settings screen
91  *
92  * @deprecated This file will be deprecated at Android S, please merge your WifiSettings
93  * in change in {@link NetworkProviderSettings}.
94  */
95 @Deprecated
96 @SearchIndexable
97 public class WifiSettings extends RestrictedSettingsFragment
98         implements Indexable, WifiPickerTracker.WifiPickerTrackerCallback,
99         WifiDialog2.WifiDialog2Listener, DialogInterface.OnDismissListener {
100 
101     private static final String TAG = "WifiSettings";
102 
103     // Set the Provider Model is always enabled
104     @VisibleForTesting
105     static Boolean IS_ENABLED_PROVIDER_MODEL = true;
106 
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_ID_SHARE = Menu.FIRST + 5;
115 
116     // Max age of tracked WifiEntries
117     private static final long MAX_SCAN_AGE_MILLIS = 15_000;
118     // Interval between initiating WifiPickerTracker scans
119     private static final long SCAN_INTERVAL_MILLIS = 10_000;
120 
121     @VisibleForTesting
122     static final int ADD_NETWORK_REQUEST = 2;
123     static final int CONFIG_NETWORK_REQUEST = 3;
124     static final int MANAGE_SUBSCRIPTION = 4;
125 
126     private static final String PREF_KEY_EMPTY_WIFI_LIST = "wifi_empty_list";
127     // TODO(b/70983952): Rename these to use WifiEntry instead of AccessPoint.
128     private static final String PREF_KEY_CONNECTED_ACCESS_POINTS = "connected_access_point";
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     private static final String PREF_KEY_STATUS_MESSAGE = "wifi_status_message";
133     @VisibleForTesting
134     static final String PREF_KEY_DATA_USAGE = "wifi_data_usage";
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 mIsWifiEntryListStale = true;
170     private final Runnable mUpdateWifiEntryPreferencesRunnable = () -> {
171         updateWifiEntryPreferences();
172     };
173     private final Runnable mHideProgressBarRunnable = () -> {
174         setProgressBarVisible(false);
175     };
176 
177     protected WifiManager mWifiManager;
178     private WifiManager.ActionListener mConnectListener;
179     private WifiManager.ActionListener mSaveListener;
180     private WifiManager.ActionListener mForgetListener;
181 
182     /**
183      * The state of {@link #isUiRestricted()} at {@link #onCreate(Bundle)}}. This is neccesary to
184      * ensure that behavior is consistent if {@link #isUiRestricted()} changes. It could be changed
185      * by the Test DPC tool in AFW mode.
186      */
187     private boolean mIsRestricted;
188 
189     private WifiEnabler mWifiEnabler;
190 
191     // Worker thread used for WifiPickerTracker work
192     private HandlerThread mWorkerThread;
193 
194     @VisibleForTesting
195     WifiPickerTracker mWifiPickerTracker;
196 
197     private WifiDialog2 mDialog;
198 
199     private View mProgressHeader;
200 
201     private PreferenceCategory mConnectedWifiEntryPreferenceCategory;
202     private PreferenceCategory mWifiEntryPreferenceCategory;
203     @VisibleForTesting
204     AddWifiNetworkPreference mAddWifiNetworkPreference;
205     @VisibleForTesting
206     Preference mConfigureWifiSettingsPreference;
207     @VisibleForTesting
208     Preference mSavedNetworksPreference;
209     @VisibleForTesting
210     DataUsagePreference mDataUsagePreference;
211     private LinkablePreference mStatusMessagePreference;
212 
213     /**
214      * Tracks whether the user initiated a connection via clicking in order to autoscroll to the
215      * network once connected.
216      */
217     private boolean mClickedConnect;
218 
WifiSettings()219     public WifiSettings() {
220         super(DISALLOW_CONFIG_WIFI);
221     }
222 
223     @Override
onViewCreated(View view, Bundle savedInstanceState)224     public void onViewCreated(View view, Bundle savedInstanceState) {
225         super.onViewCreated(view, savedInstanceState);
226         final Activity activity = getActivity();
227         if (activity != null) {
228             mProgressHeader = setPinnedHeaderView(R.layout.progress_header)
229                     .findViewById(R.id.progress_bar_animation);
230             setProgressBarVisible(false);
231         }
232         ((SettingsActivity) activity).getSwitchBar().setTitle(
233                 getContext().getString(R.string.wifi_settings_primary_switch_title));
234     }
235 
236     @Override
onCreate(Bundle icicle)237     public void onCreate(Bundle icicle) {
238         super.onCreate(icicle);
239 
240         if (IS_ENABLED_PROVIDER_MODEL) {
241             final Intent intent = new Intent("android.settings.NETWORK_PROVIDER_SETTINGS");
242             // Add FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_CLEAR_TASK to avoid multiple
243             // instances issue. (e.g. b/191956700)
244             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
245             final Bundle extras = getActivity().getIntent().getExtras();
246             if (extras != null) {
247                 intent.putExtras(extras);
248             }
249             getContext().startActivity(intent);
250             finish();
251             return;
252         }
253 
254         // TODO(b/37429702): Add animations and preference comparator back after initial screen is
255         // loaded (ODR).
256         setAnimationAllowed(false);
257 
258         addPreferences();
259 
260         mIsRestricted = isUiRestricted();
261     }
262 
addPreferences()263     private void addPreferences() {
264         addPreferencesFromResource(R.xml.wifi_settings);
265 
266         mConnectedWifiEntryPreferenceCategory = findPreference(PREF_KEY_CONNECTED_ACCESS_POINTS);
267         mWifiEntryPreferenceCategory = findPreference(PREF_KEY_ACCESS_POINTS);
268         mConfigureWifiSettingsPreference = findPreference(PREF_KEY_CONFIGURE_WIFI_SETTINGS);
269         mSavedNetworksPreference = findPreference(PREF_KEY_SAVED_NETWORKS);
270         mAddWifiNetworkPreference = new AddWifiNetworkPreference(getPrefContext());
271         mStatusMessagePreference = findPreference(PREF_KEY_STATUS_MESSAGE);
272         mDataUsagePreference = findPreference(PREF_KEY_DATA_USAGE);
273         mDataUsagePreference.setVisible(DataUsageUtils.hasWifiRadio(getContext()));
274         mDataUsagePreference.setTemplate(
275                 NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL,
276                 null /* subscriberId */), 0 /*subId*/, null /*service*/);
277     }
278 
279     @Override
onActivityCreated(Bundle savedInstanceState)280     public void onActivityCreated(Bundle savedInstanceState) {
281         super.onActivityCreated(savedInstanceState);
282 
283         final Context context = getContext();
284         mWorkerThread = new HandlerThread(TAG
285                 + "{" + Integer.toHexString(System.identityHashCode(this)) + "}",
286                 Process.THREAD_PRIORITY_BACKGROUND);
287         mWorkerThread.start();
288         final Clock elapsedRealtimeClock = new SimpleClock(ZoneOffset.UTC) {
289             @Override
290             public long millis() {
291                 return SystemClock.elapsedRealtime();
292             }
293         };
294         mWifiPickerTracker = FeatureFactory.getFactory(context)
295                 .getWifiTrackerLibProvider()
296                 .createWifiPickerTracker(getSettingsLifecycle(), context,
297                         new Handler(Looper.getMainLooper()),
298                         mWorkerThread.getThreadHandler(),
299                         elapsedRealtimeClock,
300                         MAX_SCAN_AGE_MILLIS,
301                         SCAN_INTERVAL_MILLIS,
302                         this);
303 
304         final Activity activity = getActivity();
305 
306         if (activity != null) {
307             mWifiManager = getActivity().getSystemService(WifiManager.class);
308         }
309 
310         mConnectListener = new WifiConnectListener(getActivity());
311 
312         mSaveListener = new WifiManager.ActionListener() {
313             @Override
314             public void onSuccess() {
315             }
316 
317             @Override
318             public void onFailure(int reason) {
319                 Activity activity = getActivity();
320                 if (activity != null) {
321                     Toast.makeText(activity,
322                             R.string.wifi_failed_save_message,
323                             Toast.LENGTH_SHORT).show();
324                 }
325             }
326         };
327 
328         mForgetListener = new WifiManager.ActionListener() {
329             @Override
330             public void onSuccess() {
331             }
332 
333             @Override
334             public void onFailure(int reason) {
335                 Activity activity = getActivity();
336                 if (activity != null) {
337                     Toast.makeText(activity,
338                             R.string.wifi_failed_forget_message,
339                             Toast.LENGTH_SHORT).show();
340                 }
341             }
342         };
343         registerForContextMenu(getListView());
344         setHasOptionsMenu(true);
345 
346         if (savedInstanceState != null) {
347             mDialogMode = savedInstanceState.getInt(SAVE_DIALOG_MODE);
348             mDialogWifiEntryKey = savedInstanceState.getString(SAVE_DIALOG_WIFIENTRY_KEY);
349         }
350 
351         // If we're supposed to enable/disable the Next button based on our current connection
352         // state, start it off in the right state.
353         final Intent intent = getActivity().getIntent();
354         mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false);
355 
356         if (intent.hasExtra(EXTRA_START_CONNECT_SSID)) {
357             mOpenSsid = intent.getStringExtra(EXTRA_START_CONNECT_SSID);
358         }
359 
360         // After rebooting the device, the Wi-Fi state will not be called back in the airplane
361         // mode, need to call onWifiStateChanged() to update the initial state of the UI.
362         onWifiStateChanged();
363     }
364 
365     @Override
onDestroyView()366     public void onDestroyView() {
367         if (mWifiEnabler != null) {
368             mWifiEnabler.teardownSwitchController();
369         }
370         mWorkerThread.quit();
371 
372         super.onDestroyView();
373     }
374 
375     @Override
onStart()376     public void onStart() {
377         super.onStart();
378 
379         mWifiEnabler = createWifiEnabler();
380 
381         if (mIsRestricted) {
382             restrictUi();
383         }
384     }
385 
restrictUi()386     private void restrictUi() {
387         if (!isUiRestrictedByOnlyAdmin()) {
388             getEmptyTextView().setText(R.string.wifi_empty_list_user_restricted);
389         }
390         getPreferenceScreen().removeAll();
391     }
392 
393     /**
394      * @return new WifiEnabler
395      */
createWifiEnabler()396     private WifiEnabler createWifiEnabler() {
397         final SettingsActivity activity = (SettingsActivity) getActivity();
398         return new WifiEnabler(activity, new MainSwitchBarController(activity.getSwitchBar()),
399                 mMetricsFeatureProvider);
400     }
401 
402     @Override
onResume()403     public void onResume() {
404         final Activity activity = getActivity();
405         super.onResume();
406 
407         // Because RestrictedSettingsFragment's onResume potentially requests authorization,
408         // which changes the restriction state, recalculate it.
409         final boolean alreadyImmutablyRestricted = mIsRestricted;
410         mIsRestricted = isUiRestricted();
411         if (!alreadyImmutablyRestricted && mIsRestricted) {
412             restrictUi();
413         }
414 
415         if (mWifiEnabler != null) {
416             mWifiEnabler.resume(activity);
417         }
418 
419         changeNextButtonState(mWifiPickerTracker.getConnectedWifiEntry() != null);
420     }
421 
422     @Override
onPause()423     public void onPause() {
424         super.onPause();
425         if (mWifiEnabler != null) {
426             mWifiEnabler.pause();
427         }
428     }
429 
430     @Override
onStop()431     public void onStop() {
432         getView().removeCallbacks(mUpdateWifiEntryPreferencesRunnable);
433         getView().removeCallbacks(mHideProgressBarRunnable);
434         mIsWifiEntryListStale = true;
435         super.onStop();
436     }
437 
438     @Override
onActivityResult(int requestCode, int resultCode, Intent data)439     public void onActivityResult(int requestCode, int resultCode, Intent data) {
440         super.onActivityResult(requestCode, resultCode, data);
441 
442         if (requestCode == ADD_NETWORK_REQUEST) {
443             handleAddNetworkRequest(resultCode, data);
444             return;
445         } else if (requestCode == REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER) {
446             if (resultCode == Activity.RESULT_OK) {
447                 if (mDialog != null) {
448                     mDialog.dismiss();
449                 }
450             }
451             return;
452         } else if (requestCode == CONFIG_NETWORK_REQUEST) {
453             if (resultCode == Activity.RESULT_OK) {
454                 final WifiConfiguration wifiConfiguration = data.getParcelableExtra(
455                         ConfigureWifiEntryFragment.NETWORK_CONFIG_KEY);
456                 if (wifiConfiguration != null) {
457                     mWifiManager.connect(wifiConfiguration,
458                             new WifiConnectActionListener());
459                 }
460             }
461             return;
462         } else if (requestCode == MANAGE_SUBSCRIPTION) {
463             //Do nothing
464             return;
465         }
466 
467         final boolean formerlyRestricted = mIsRestricted;
468         mIsRestricted = isUiRestricted();
469         if (formerlyRestricted && !mIsRestricted
470                 && getPreferenceScreen().getPreferenceCount() == 0) {
471             // De-restrict the ui
472             addPreferences();
473         }
474     }
475 
476     @Override
onCreateAdapter(PreferenceScreen preferenceScreen)477     protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
478         final RecyclerView.Adapter adapter = super.onCreateAdapter(preferenceScreen);
479         adapter.setHasStableIds(true);
480         return adapter;
481     }
482 
483     @Override
getMetricsCategory()484     public int getMetricsCategory() {
485         return SettingsEnums.WIFI;
486     }
487 
488     @Override
onSaveInstanceState(Bundle outState)489     public void onSaveInstanceState(Bundle outState) {
490         super.onSaveInstanceState(outState);
491         // If dialog has been shown, save its state.
492         if (mDialog != null) {
493             outState.putInt(SAVE_DIALOG_MODE, mDialogMode);
494             outState.putString(SAVE_DIALOG_WIFIENTRY_KEY, mDialogWifiEntryKey);
495         }
496     }
497 
498     @Override
onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info)499     public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
500         Preference preference = (Preference) view.getTag();
501         if (!(preference instanceof LongPressWifiEntryPreference)) {
502             // Do nothing.
503             return;
504         }
505 
506         // Cache the WifiEntry for onContextItemSelected. Don't use it in other methods.
507         mSelectedWifiEntry = ((LongPressWifiEntryPreference) preference).getWifiEntry();
508 
509         menu.setHeaderTitle(mSelectedWifiEntry.getTitle());
510         if (mSelectedWifiEntry.canConnect()) {
511             menu.add(Menu.NONE, MENU_ID_CONNECT, 0 /* order */, R.string.wifi_connect);
512         }
513 
514         if (mSelectedWifiEntry.canDisconnect()) {
515             menu.add(Menu.NONE, MENU_ID_SHARE, 0 /* order */, R.string.share);
516             menu.add(Menu.NONE, MENU_ID_DISCONNECT, 1 /* order */,
517                     R.string.wifi_disconnect_button_text);
518         }
519 
520         // "forget" for normal saved network. And "disconnect" for ephemeral network because it
521         // could only be disconnected and be put in blocklists so it won't be used again.
522         if (canForgetNetwork()) {
523             menu.add(Menu.NONE, MENU_ID_FORGET, 0 /* order */, R.string.forget);
524         }
525 
526         WifiConfiguration config = mSelectedWifiEntry.getWifiConfiguration();
527         // Some configs are ineditable
528         if (WifiUtils.isNetworkLockedDown(getActivity(), config)) {
529             return;
530         }
531 
532         if (mSelectedWifiEntry.isSaved() && mSelectedWifiEntry.getConnectedState()
533                 != WifiEntry.CONNECTED_STATE_CONNECTED) {
534             menu.add(Menu.NONE, MENU_ID_MODIFY, 0 /* order */, R.string.wifi_modify);
535         }
536     }
537 
canForgetNetwork()538     private boolean canForgetNetwork() {
539         return mSelectedWifiEntry.canForget() && !WifiUtils.isNetworkLockedDown(getActivity(),
540                 mSelectedWifiEntry.getWifiConfiguration());
541     }
542 
543     @Override
onContextItemSelected(MenuItem item)544     public boolean onContextItemSelected(MenuItem item) {
545         switch (item.getItemId()) {
546             case MENU_ID_CONNECT:
547                 connect(mSelectedWifiEntry, true /* editIfNoConfig */, false /* fullScreenEdit */);
548                 return true;
549             case MENU_ID_DISCONNECT:
550                 mSelectedWifiEntry.disconnect(null /* callback */);
551                 return true;
552             case MENU_ID_FORGET:
553                 forget(mSelectedWifiEntry);
554                 return true;
555             case MENU_ID_SHARE:
556                 WifiDppUtils.showLockScreen(getContext(),
557                         () -> launchWifiDppConfiguratorActivity(mSelectedWifiEntry));
558                 return true;
559             case MENU_ID_MODIFY:
560                 showDialog(mSelectedWifiEntry, WifiConfigUiBase2.MODE_MODIFY);
561                 return true;
562             default:
563                 return super.onContextItemSelected(item);
564         }
565     }
566 
567     @Override
onPreferenceTreeClick(Preference preference)568     public boolean onPreferenceTreeClick(Preference preference) {
569         // If the preference has a fragment set, open that
570         if (preference.getFragment() != null) {
571             preference.setOnPreferenceClickListener(null);
572             return super.onPreferenceTreeClick(preference);
573         }
574 
575         if (preference instanceof LongPressWifiEntryPreference) {
576             final WifiEntry selectedEntry =
577                     ((LongPressWifiEntryPreference) preference).getWifiEntry();
578 
579             if (selectedEntry.shouldEditBeforeConnect()) {
580                 launchConfigNewNetworkFragment(selectedEntry);
581                 return true;
582             }
583 
584             connect(selectedEntry, true /* editIfNoConfig */, true /* fullScreenEdit */);
585         } else if (preference == mAddWifiNetworkPreference) {
586             onAddNetworkPressed();
587         } else {
588             return super.onPreferenceTreeClick(preference);
589         }
590         return true;
591     }
592 
showDialog(WifiEntry wifiEntry, int dialogMode)593     private void showDialog(WifiEntry wifiEntry, int dialogMode) {
594         if (WifiUtils.isNetworkLockedDown(getActivity(), wifiEntry.getWifiConfiguration())
595                 && wifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) {
596             RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(),
597                     RestrictedLockUtilsInternal.getDeviceOwner(getActivity()));
598             return;
599         }
600 
601         if (mDialog != null) {
602             removeDialog(WIFI_DIALOG_ID);
603             mDialog = null;
604         }
605 
606         // Save the access point and edit mode
607         mDialogWifiEntry = wifiEntry;
608         mDialogWifiEntryKey = wifiEntry.getKey();
609         mDialogMode = dialogMode;
610 
611         showDialog(WIFI_DIALOG_ID);
612     }
613 
614     @Override
onCreateDialog(int dialogId)615     public Dialog onCreateDialog(int dialogId) {
616         switch (dialogId) {
617             case WIFI_DIALOG_ID:
618                 // modify network
619                 mDialog = WifiDialog2
620                         .createModal(getActivity(), this, mDialogWifiEntry, mDialogMode);
621                 return mDialog;
622             default:
623                 return super.onCreateDialog(dialogId);
624         }
625     }
626 
627     @Override
onDialogShowing()628     public void onDialogShowing() {
629         super.onDialogShowing();
630         setOnDismissListener(this);
631     }
632 
633     @Override
onDismiss(DialogInterface dialog)634     public void onDismiss(DialogInterface dialog) {
635         // We don't keep any dialog object when dialog was dismissed.
636         mDialog = null;
637         mDialogWifiEntry = null;
638         mDialogWifiEntryKey = null;
639     }
640 
641     @Override
getDialogMetricsCategory(int dialogId)642     public int getDialogMetricsCategory(int dialogId) {
643         switch (dialogId) {
644             case WIFI_DIALOG_ID:
645                 return SettingsEnums.DIALOG_WIFI_AP_EDIT;
646             default:
647                 return 0;
648         }
649     }
650 
651     /** Called when the state of Wifi has changed. */
652     @Override
onWifiStateChanged()653     public void onWifiStateChanged() {
654         if (mIsRestricted) {
655             return;
656         }
657         final int wifiState = mWifiPickerTracker.getWifiState();
658 
659         if (isVerboseLoggingEnabled()) {
660             Log.i(TAG, "onWifiStateChanged called with wifi state: " + wifiState);
661         }
662 
663         switch (wifiState) {
664             case WifiManager.WIFI_STATE_ENABLED:
665                 updateWifiEntryPreferences();
666                 break;
667 
668             case WifiManager.WIFI_STATE_ENABLING:
669                 removeConnectedWifiEntryPreference();
670                 removeWifiEntryPreference();
671                 addMessagePreference(R.string.wifi_starting);
672                 setProgressBarVisible(true);
673                 break;
674 
675             case WifiManager.WIFI_STATE_DISABLING:
676                 removeConnectedWifiEntryPreference();
677                 removeWifiEntryPreference();
678                 addMessagePreference(R.string.wifi_stopping);
679                 break;
680 
681             case WifiManager.WIFI_STATE_DISABLED:
682                 setOffMessage();
683                 setAdditionalSettingsSummaries();
684                 setProgressBarVisible(false);
685                 mClickedConnect = false;
686                 break;
687         }
688     }
689 
690     @Override
onWifiEntriesChanged()691     public void onWifiEntriesChanged() {
692         if (mIsWifiEntryListStale) {
693             mIsWifiEntryListStale = false;
694             updateWifiEntryPreferences();
695         } else {
696             updateWifiEntryPreferencesDelayed();
697         }
698         changeNextButtonState(mWifiPickerTracker.getConnectedWifiEntry() != null);
699 
700         // Edit the Wi-Fi network of specified SSID.
701         if (mOpenSsid != null) {
702             Optional<WifiEntry> matchedWifiEntry = mWifiPickerTracker.getWifiEntries().stream()
703                     .filter(wifiEntry -> TextUtils.equals(mOpenSsid, wifiEntry.getSsid()))
704                     .filter(wifiEntry -> wifiEntry.getSecurity() != WifiEntry.SECURITY_NONE
705                             && wifiEntry.getSecurity() != WifiEntry.SECURITY_OWE)
706                     .filter(wifiEntry -> !wifiEntry.isSaved()
707                             || isDisabledByWrongPassword(wifiEntry))
708                     .findFirst();
709             if (matchedWifiEntry.isPresent()) {
710                 mOpenSsid = null;
711                 launchConfigNewNetworkFragment(matchedWifiEntry.get());
712             }
713         }
714     }
715 
716     @Override
onNumSavedNetworksChanged()717     public void onNumSavedNetworksChanged() {
718         if (isFinishingOrDestroyed()) {
719             return;
720         }
721         setAdditionalSettingsSummaries();
722     }
723 
724     @Override
onNumSavedSubscriptionsChanged()725     public void onNumSavedSubscriptionsChanged() {
726         if (isFinishingOrDestroyed()) {
727             return;
728         }
729         setAdditionalSettingsSummaries();
730     }
731 
732     /**
733      * Updates WifiEntries from {@link WifiPickerTracker#getWifiEntries()}. Adds a delay to have
734      * progress bar displayed before starting to modify entries.
735      */
updateWifiEntryPreferencesDelayed()736     private void updateWifiEntryPreferencesDelayed() {
737         // Safeguard from some delayed event handling
738         if (getActivity() != null && !mIsRestricted
739                 && mWifiPickerTracker.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
740             final View view = getView();
741             final Handler handler = view.getHandler();
742             if (handler != null && handler.hasCallbacks(mUpdateWifiEntryPreferencesRunnable)) {
743                 return;
744             }
745             setProgressBarVisible(true);
746             view.postDelayed(mUpdateWifiEntryPreferencesRunnable, 300);
747         }
748     }
749 
updateWifiEntryPreferences()750     private void updateWifiEntryPreferences() {
751         // in case state has changed
752         if (mWifiPickerTracker.getWifiState() != WifiManager.WIFI_STATE_ENABLED) {
753             return;
754         }
755 
756         boolean hasAvailableWifiEntries = false;
757         mStatusMessagePreference.setVisible(false);
758         mWifiEntryPreferenceCategory.setVisible(true);
759 
760         final WifiEntry connectedEntry = mWifiPickerTracker.getConnectedWifiEntry();
761         mConnectedWifiEntryPreferenceCategory.setVisible(connectedEntry != null);
762         if (connectedEntry != null) {
763             final LongPressWifiEntryPreference connectedPref =
764                     mConnectedWifiEntryPreferenceCategory.findPreference(connectedEntry.getKey());
765             if (connectedPref == null || connectedPref.getWifiEntry() != connectedEntry) {
766                 mConnectedWifiEntryPreferenceCategory.removeAll();
767                 final ConnectedWifiEntryPreference pref =
768                         new ConnectedWifiEntryPreference(getPrefContext(), connectedEntry, this);
769                 pref.setKey(connectedEntry.getKey());
770                 pref.refresh();
771                 mConnectedWifiEntryPreferenceCategory.addPreference(pref);
772                 pref.setOnPreferenceClickListener(preference -> {
773                     if (connectedEntry.canSignIn()) {
774                         connectedEntry.signIn(null /* callback */);
775                     } else {
776                         launchNetworkDetailsFragment(pref);
777                     }
778                     return true;
779                 });
780                 pref.setOnGearClickListener(preference -> {
781                     launchNetworkDetailsFragment(pref);
782                 });
783 
784                 if (mClickedConnect) {
785                     mClickedConnect = false;
786                     scrollToPreference(mConnectedWifiEntryPreferenceCategory);
787                 }
788             }
789         } else {
790             mConnectedWifiEntryPreferenceCategory.removeAll();
791         }
792 
793         int index = 0;
794         cacheRemoveAllPrefs(mWifiEntryPreferenceCategory);
795         List<WifiEntry> wifiEntries = mWifiPickerTracker.getWifiEntries();
796         for (WifiEntry wifiEntry : wifiEntries) {
797             hasAvailableWifiEntries = true;
798 
799             String key = wifiEntry.getKey();
800             LongPressWifiEntryPreference pref =
801                     (LongPressWifiEntryPreference) getCachedPreference(key);
802             if (pref != null) {
803                 if (pref.getWifiEntry() == wifiEntry) {
804                     pref.setOrder(index++);
805                     continue;
806                 } else {
807                     // Create a new preference if the underlying WifiEntry object has changed
808                     removePreference(key);
809                 }
810             }
811 
812             pref = createLongPressWifiEntryPreference(wifiEntry);
813             pref.setKey(wifiEntry.getKey());
814             pref.setOrder(index++);
815             pref.refresh();
816 
817             if (wifiEntry.getHelpUriString() != null) {
818                 pref.setOnButtonClickListener(preference -> {
819                     openSubscriptionHelpPage(wifiEntry);
820                 });
821             }
822             mWifiEntryPreferenceCategory.addPreference(pref);
823         }
824         removeCachedPrefs(mWifiEntryPreferenceCategory);
825 
826         if (!hasAvailableWifiEntries) {
827             setProgressBarVisible(true);
828             Preference pref = new Preference(getPrefContext());
829             pref.setSelectable(false);
830             pref.setSummary(R.string.wifi_empty_list_wifi_on);
831             pref.setOrder(index++);
832             pref.setKey(PREF_KEY_EMPTY_WIFI_LIST);
833             mWifiEntryPreferenceCategory.addPreference(pref);
834         } else {
835             // Continuing showing progress bar for an additional delay to overlap with animation
836             getView().postDelayed(mHideProgressBarRunnable, 1700 /* delay millis */);
837         }
838 
839         mAddWifiNetworkPreference.setOrder(index++);
840         mWifiEntryPreferenceCategory.addPreference(mAddWifiNetworkPreference);
841         setAdditionalSettingsSummaries();
842     }
843 
launchNetworkDetailsFragment(LongPressWifiEntryPreference pref)844     private void launchNetworkDetailsFragment(LongPressWifiEntryPreference pref) {
845         final WifiEntry wifiEntry = pref.getWifiEntry();
846         final Context context = getContext();
847         final CharSequence title =
848                 FeatureFlagUtils.isEnabled(context, FeatureFlags.WIFI_DETAILS_DATAUSAGE_HEADER)
849                         ? wifiEntry.getTitle()
850                         : context.getText(R.string.pref_title_network_details);
851 
852         final Bundle bundle = new Bundle();
853         bundle.putString(WifiNetworkDetailsFragment.KEY_CHOSEN_WIFIENTRY_KEY, wifiEntry.getKey());
854 
855         new SubSettingLauncher(context)
856                 .setTitleText(title)
857                 .setDestination(WifiNetworkDetailsFragment.class.getName())
858                 .setArguments(bundle)
859                 .setSourceMetricsCategory(getMetricsCategory())
860                 .launch();
861     }
862 
863     @VisibleForTesting
createLongPressWifiEntryPreference(WifiEntry wifiEntry)864     LongPressWifiEntryPreference createLongPressWifiEntryPreference(WifiEntry wifiEntry) {
865         return new LongPressWifiEntryPreference(getPrefContext(), wifiEntry, this);
866     }
867 
launchAddNetworkFragment()868     private void launchAddNetworkFragment() {
869         new SubSettingLauncher(getContext())
870                 .setTitleRes(R.string.wifi_add_network)
871                 .setDestination(AddNetworkFragment.class.getName())
872                 .setSourceMetricsCategory(getMetricsCategory())
873                 .setResultListener(this, ADD_NETWORK_REQUEST)
874                 .launch();
875     }
876 
877     /** Removes all preferences and hide the {@link #mConnectedWifiEntryPreferenceCategory}. */
removeConnectedWifiEntryPreference()878     private void removeConnectedWifiEntryPreference() {
879         mConnectedWifiEntryPreferenceCategory.removeAll();
880         mConnectedWifiEntryPreferenceCategory.setVisible(false);
881     }
882 
removeWifiEntryPreference()883     private void removeWifiEntryPreference() {
884         mWifiEntryPreferenceCategory.removeAll();
885         mWifiEntryPreferenceCategory.setVisible(false);
886     }
887 
888     @VisibleForTesting
setAdditionalSettingsSummaries()889     void setAdditionalSettingsSummaries() {
890         mConfigureWifiSettingsPreference.setSummary(getString(
891                 isWifiWakeupEnabled()
892                         ? R.string.wifi_configure_settings_preference_summary_wakeup_on
893                         : R.string.wifi_configure_settings_preference_summary_wakeup_off));
894 
895         final int numSavedNetworks = mWifiPickerTracker.getNumSavedNetworks();
896         final int numSavedSubscriptions = mWifiPickerTracker.getNumSavedSubscriptions();
897         if (numSavedNetworks + numSavedSubscriptions > 0) {
898             mSavedNetworksPreference.setVisible(true);
899             mSavedNetworksPreference.setSummary(
900                     getSavedNetworkSettingsSummaryText(numSavedNetworks, numSavedSubscriptions));
901         } else {
902             mSavedNetworksPreference.setVisible(false);
903         }
904     }
905 
getSavedNetworkSettingsSummaryText( int numSavedNetworks, int numSavedSubscriptions)906     private String getSavedNetworkSettingsSummaryText(
907             int numSavedNetworks, int numSavedSubscriptions) {
908         if (numSavedSubscriptions == 0) {
909             return getResources().getQuantityString(R.plurals.wifi_saved_access_points_summary,
910                     numSavedNetworks, numSavedNetworks);
911         } else if (numSavedNetworks == 0) {
912             return getResources().getQuantityString(
913                     R.plurals.wifi_saved_passpoint_access_points_summary,
914                     numSavedSubscriptions, numSavedSubscriptions);
915         } else {
916             final int numTotalEntries = numSavedNetworks + numSavedSubscriptions;
917             return getResources().getQuantityString(R.plurals.wifi_saved_all_access_points_summary,
918                     numTotalEntries, numTotalEntries);
919         }
920     }
921 
isWifiWakeupEnabled()922     private boolean isWifiWakeupEnabled() {
923         final Context context = getContext();
924         final PowerManager powerManager = context.getSystemService(PowerManager.class);
925         final ContentResolver contentResolver = context.getContentResolver();
926         return mWifiManager.isAutoWakeupEnabled()
927                 && mWifiManager.isScanAlwaysAvailable()
928                 && Settings.Global.getInt(contentResolver,
929                 Settings.Global.AIRPLANE_MODE_ON, 0) == 0
930                 && !powerManager.isPowerSaveMode();
931     }
932 
setOffMessage()933     private void setOffMessage() {
934         final CharSequence title = getText(R.string.wifi_empty_list_wifi_off);
935         // Don't use WifiManager.isScanAlwaysAvailable() to check the Wi-Fi scanning mode. Instead,
936         // read the system settings directly. Because when the device is in Airplane mode, even if
937         // Wi-Fi scanning mode is on, WifiManager.isScanAlwaysAvailable() still returns "off".
938         // TODO(b/149421497): Fix this?
939         final boolean wifiScanningMode = mWifiManager.isScanAlwaysAvailable();
940         final CharSequence description = wifiScanningMode ? getText(R.string.wifi_scan_notify_text)
941                 : getText(R.string.wifi_scan_notify_text_scanning_off);
942         final LinkifyUtils.OnClickListener clickListener =
943                 () -> new SubSettingLauncher(getContext())
944                         .setDestination(WifiScanningFragment.class.getName())
945                         .setTitleRes(R.string.location_scanning_wifi_always_scanning_title)
946                         .setSourceMetricsCategory(getMetricsCategory())
947                         .launch();
948         mStatusMessagePreference.setText(title, description, clickListener);
949         removeConnectedWifiEntryPreference();
950         removeWifiEntryPreference();
951         mStatusMessagePreference.setVisible(true);
952     }
953 
addMessagePreference(int messageId)954     private void addMessagePreference(int messageId) {
955         mStatusMessagePreference.setTitle(messageId);
956         mStatusMessagePreference.setVisible(true);
957 
958     }
959 
setProgressBarVisible(boolean visible)960     protected void setProgressBarVisible(boolean visible) {
961         if (mProgressHeader != null) {
962             mProgressHeader.setVisibility(visible ? View.VISIBLE : View.GONE);
963         }
964     }
965 
966     @VisibleForTesting
handleAddNetworkRequest(int result, Intent data)967     void handleAddNetworkRequest(int result, Intent data) {
968         if (result == Activity.RESULT_OK) {
969             handleAddNetworkSubmitEvent(data);
970         }
971     }
972 
handleAddNetworkSubmitEvent(Intent data)973     private void handleAddNetworkSubmitEvent(Intent data) {
974         final WifiConfiguration wifiConfiguration = data.getParcelableExtra(
975                 AddNetworkFragment.WIFI_CONFIG_KEY);
976         if (wifiConfiguration != null) {
977             mWifiManager.save(wifiConfiguration, mSaveListener);
978         }
979     }
980 
981     /**
982      * Called when "add network" button is pressed.
983      */
onAddNetworkPressed()984     private void onAddNetworkPressed() {
985         launchAddNetworkFragment();
986     }
987 
988     @Override
getHelpResource()989     public int getHelpResource() {
990         return R.string.help_url_wifi;
991     }
992 
993     /**
994      * Renames/replaces "Next" button when appropriate. "Next" button usually exists in
995      * Wi-Fi setup screens, not in usual wifi settings screen.
996      *
997      * @param enabled true when the device is connected to a wifi network.
998      */
999     @VisibleForTesting
changeNextButtonState(boolean enabled)1000     void changeNextButtonState(boolean enabled) {
1001         if (mEnableNextOnConnection && hasNextButton()) {
1002             getNextButton().setEnabled(enabled);
1003         }
1004     }
1005 
1006     @Override
onForget(WifiDialog2 dialog)1007     public void onForget(WifiDialog2 dialog) {
1008         forget(dialog.getWifiEntry());
1009     }
1010 
1011     @Override
onSubmit(WifiDialog2 dialog)1012     public void onSubmit(WifiDialog2 dialog) {
1013         final int dialogMode = dialog.getMode();
1014         final WifiConfiguration config = dialog.getController().getConfig();
1015         final WifiEntry wifiEntry = dialog.getWifiEntry();
1016 
1017         if (dialogMode == WifiConfigUiBase2.MODE_MODIFY) {
1018             if (config == null) {
1019                 Toast.makeText(getContext(), R.string.wifi_failed_save_message,
1020                         Toast.LENGTH_SHORT).show();
1021             } else {
1022                 mWifiManager.save(config, mSaveListener);
1023             }
1024         } else if (dialogMode == WifiConfigUiBase2.MODE_CONNECT
1025                 || (dialogMode == WifiConfigUiBase2.MODE_VIEW && wifiEntry.canConnect())) {
1026             if (config == null) {
1027                 connect(wifiEntry, false /* editIfNoConfig */,
1028                         false /* fullScreenEdit*/);
1029             } else {
1030                 mWifiManager.connect(config, new WifiConnectActionListener());
1031             }
1032         }
1033     }
1034 
1035     @Override
onScan(WifiDialog2 dialog, String ssid)1036     public void onScan(WifiDialog2 dialog, String ssid) {
1037         // Launch QR code scanner to join a network.
1038         startActivityForResult(
1039                 WifiDppUtils.getEnrolleeQrCodeScannerIntent(dialog.getContext(), ssid),
1040                 REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER);
1041     }
1042 
forget(WifiEntry wifiEntry)1043     private void forget(WifiEntry wifiEntry) {
1044         mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_WIFI_FORGET);
1045         wifiEntry.forget(null /* callback */);
1046     }
1047 
1048     @VisibleForTesting
connect(WifiEntry wifiEntry, boolean editIfNoConfig, boolean fullScreenEdit)1049     void connect(WifiEntry wifiEntry, boolean editIfNoConfig, boolean fullScreenEdit) {
1050         mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_WIFI_CONNECT,
1051                 wifiEntry.isSaved());
1052 
1053         // If it's an unsaved secure WifiEntry, it will callback
1054         // ConnectCallback#onConnectResult with ConnectCallback#CONNECT_STATUS_FAILURE_NO_CONFIG
1055         wifiEntry.connect(new WifiEntryConnectCallback(wifiEntry, editIfNoConfig,
1056                 fullScreenEdit));
1057     }
1058 
1059     private class WifiConnectActionListener implements WifiManager.ActionListener {
1060         @Override
onSuccess()1061         public void onSuccess() {
1062             mClickedConnect = true;
1063         }
1064 
1065         @Override
onFailure(int reason)1066         public void onFailure(int reason) {
1067             if (isFinishingOrDestroyed()) {
1068                 return;
1069             }
1070             Toast.makeText(getContext(), R.string.wifi_failed_connect_message, Toast.LENGTH_SHORT)
1071                     .show();
1072         }
1073     }
1074 
1075     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
1076             new BaseSearchIndexProvider(R.xml.wifi_settings) {
1077                 @Override
1078                 protected boolean isPageSearchEnabled(Context context) {
1079                     return !IS_ENABLED_PROVIDER_MODEL;
1080                 }
1081 
1082                 @Override
1083                 public List<String> getNonIndexableKeys(Context context) {
1084                     final List<String> keys = super.getNonIndexableKeys(context);
1085 
1086                     final WifiManager wifiManager = context.getSystemService(WifiManager.class);
1087                     if (WifiSavedConfigUtils.getAllConfigsCount(context, wifiManager) == 0) {
1088                         keys.add(PREF_KEY_SAVED_NETWORKS);
1089                     }
1090 
1091                     if (!DataUsageUtils.hasWifiRadio(context)) {
1092                         keys.add(PREF_KEY_DATA_USAGE);
1093                     }
1094                     return keys;
1095                 }
1096             };
1097 
1098     private class WifiEntryConnectCallback implements ConnectCallback {
1099         final WifiEntry mConnectWifiEntry;
1100         final boolean mEditIfNoConfig;
1101         final boolean mFullScreenEdit;
1102 
WifiEntryConnectCallback(WifiEntry connectWifiEntry, boolean editIfNoConfig, boolean fullScreenEdit)1103         WifiEntryConnectCallback(WifiEntry connectWifiEntry, boolean editIfNoConfig,
1104                 boolean fullScreenEdit) {
1105             mConnectWifiEntry = connectWifiEntry;
1106             mEditIfNoConfig = editIfNoConfig;
1107             mFullScreenEdit = fullScreenEdit;
1108         }
1109 
1110         @Override
onConnectResult(@onnectStatus int status)1111         public void onConnectResult(@ConnectStatus int status) {
1112             if (isFinishingOrDestroyed()) {
1113                 return;
1114             }
1115 
1116             if (status == ConnectCallback.CONNECT_STATUS_SUCCESS) {
1117                 mClickedConnect = true;
1118             } else if (status == ConnectCallback.CONNECT_STATUS_FAILURE_NO_CONFIG) {
1119                 if (mEditIfNoConfig) {
1120                     // Edit an unsaved secure Wi-Fi network.
1121                     if (mFullScreenEdit) {
1122                         launchConfigNewNetworkFragment(mConnectWifiEntry);
1123                     } else {
1124                         showDialog(mConnectWifiEntry, WifiConfigUiBase2.MODE_CONNECT);
1125                     }
1126                 }
1127             } else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) {
1128                 Toast.makeText(getContext(), R.string.wifi_failed_connect_message,
1129                         Toast.LENGTH_SHORT).show();
1130             }
1131         }
1132     }
1133 
launchConfigNewNetworkFragment(WifiEntry wifiEntry)1134     private void launchConfigNewNetworkFragment(WifiEntry wifiEntry) {
1135         final Bundle bundle = new Bundle();
1136         bundle.putString(WifiNetworkDetailsFragment.KEY_CHOSEN_WIFIENTRY_KEY,
1137                 wifiEntry.getKey());
1138         new SubSettingLauncher(getContext())
1139                 .setTitleText(wifiEntry.getTitle())
1140                 .setDestination(ConfigureWifiEntryFragment.class.getName())
1141                 .setArguments(bundle)
1142                 .setSourceMetricsCategory(getMetricsCategory())
1143                 .setResultListener(WifiSettings.this, CONFIG_NETWORK_REQUEST)
1144                 .launch();
1145     }
1146 
launchWifiDppConfiguratorActivity(WifiEntry wifiEntry)1147     private void launchWifiDppConfiguratorActivity(WifiEntry wifiEntry) {
1148         final Intent intent = WifiDppUtils.getConfiguratorQrCodeGeneratorIntentOrNull(getContext(),
1149                 mWifiManager, wifiEntry);
1150 
1151         if (intent == null) {
1152             Log.e(TAG, "Launch Wi-Fi DPP QR code generator with a wrong Wi-Fi network!");
1153         } else {
1154             mMetricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN,
1155                     SettingsEnums.ACTION_SETTINGS_SHARE_WIFI_QR_CODE,
1156                     SettingsEnums.SETTINGS_WIFI_DPP_CONFIGURATOR,
1157                     /* key */ null,
1158                     /* value */ Integer.MIN_VALUE);
1159 
1160             startActivity(intent);
1161         }
1162     }
1163 
1164     /** Helper method to return whether a WifiEntry is disabled due to a wrong password */
isDisabledByWrongPassword(WifiEntry wifiEntry)1165     private static boolean isDisabledByWrongPassword(WifiEntry wifiEntry) {
1166         WifiConfiguration config = wifiEntry.getWifiConfiguration();
1167         if (config == null) {
1168             return false;
1169         }
1170         WifiConfiguration.NetworkSelectionStatus networkStatus =
1171                 config.getNetworkSelectionStatus();
1172         if (networkStatus == null
1173                 || networkStatus.getNetworkSelectionStatus() == NETWORK_SELECTION_ENABLED) {
1174             return false;
1175         }
1176         int reason = networkStatus.getNetworkSelectionDisableReason();
1177         return WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD == reason;
1178     }
1179 
1180     @VisibleForTesting
openSubscriptionHelpPage(WifiEntry wifiEntry)1181     void openSubscriptionHelpPage(WifiEntry wifiEntry) {
1182         final Intent intent = getHelpIntent(getContext(), wifiEntry.getHelpUriString());
1183         if (intent != null) {
1184             try {
1185                 startActivityForResult(intent, MANAGE_SUBSCRIPTION);
1186             } catch (ActivityNotFoundException e) {
1187                 Log.e(TAG, "Activity was not found for intent, " + intent.toString());
1188             }
1189         }
1190     }
1191 
1192     @VisibleForTesting
getHelpIntent(Context context, String helpUrlString)1193     Intent getHelpIntent(Context context, String helpUrlString) {
1194         return HelpUtils.getHelpIntent(context, helpUrlString, context.getClass().getName());
1195     }
1196 }
1197