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