1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.wifi; 18 19 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 20 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED; 21 import static android.os.UserManager.DISALLOW_CONFIG_WIFI; 22 23 import android.annotation.NonNull; 24 import android.app.Activity; 25 import android.app.Dialog; 26 import android.app.settings.SettingsEnums; 27 import android.content.ContentResolver; 28 import android.content.Context; 29 import android.content.DialogInterface; 30 import android.content.Intent; 31 import android.net.ConnectivityManager; 32 import android.net.Network; 33 import android.net.NetworkInfo; 34 import android.net.NetworkInfo.State; 35 import android.net.NetworkRequest; 36 import android.net.NetworkTemplate; 37 import android.net.wifi.WifiConfiguration; 38 import android.net.wifi.WifiManager; 39 import android.os.Bundle; 40 import android.os.Handler; 41 import android.os.Looper; 42 import android.os.PowerManager; 43 import android.provider.Settings; 44 import android.util.FeatureFlagUtils; 45 import android.util.Log; 46 import android.view.ContextMenu; 47 import android.view.ContextMenu.ContextMenuInfo; 48 import android.view.Menu; 49 import android.view.MenuItem; 50 import android.view.View; 51 import android.widget.Toast; 52 53 import androidx.annotation.IntDef; 54 import androidx.annotation.VisibleForTesting; 55 import androidx.preference.Preference; 56 import androidx.preference.PreferenceCategory; 57 import androidx.preference.PreferenceScreen; 58 import androidx.recyclerview.widget.RecyclerView; 59 60 import com.android.settings.LinkifyUtils; 61 import com.android.settings.R; 62 import com.android.settings.RestrictedSettingsFragment; 63 import com.android.settings.SettingsActivity; 64 import com.android.settings.core.FeatureFlags; 65 import com.android.settings.core.SubSettingLauncher; 66 import com.android.settings.datausage.DataUsagePreference; 67 import com.android.settings.datausage.DataUsageUtils; 68 import com.android.settings.location.ScanningSettings; 69 import com.android.settings.search.BaseSearchIndexProvider; 70 import com.android.settings.widget.SwitchBarController; 71 import com.android.settings.wifi.details.WifiNetworkDetailsFragment; 72 import com.android.settings.wifi.dpp.WifiDppUtils; 73 import com.android.settingslib.RestrictedLockUtils; 74 import com.android.settingslib.RestrictedLockUtilsInternal; 75 import com.android.settingslib.search.Indexable; 76 import com.android.settingslib.search.SearchIndexable; 77 import com.android.settingslib.wifi.AccessPoint; 78 import com.android.settingslib.wifi.AccessPoint.AccessPointListener; 79 import com.android.settingslib.wifi.AccessPointPreference; 80 import com.android.settingslib.wifi.WifiSavedConfigUtils; 81 import com.android.settingslib.wifi.WifiTracker; 82 import com.android.settingslib.wifi.WifiTrackerFactory; 83 84 import java.util.List; 85 86 /** 87 * Two types of UI are provided here. 88 * 89 * The first is for "usual Settings", appearing as any other Setup fragment. 90 * 91 * The second is for Setup Wizard, with a simplified interface that hides the action bar 92 * and menus. 93 * 94 * Migrating from Wi-Fi SettingsLib to to WifiTrackerLib, this object will be removed in the near 95 * future, please develop in {@link WifiSettings2}. 96 */ 97 @SearchIndexable 98 public class WifiSettings extends RestrictedSettingsFragment 99 implements Indexable, WifiTracker.WifiListener, AccessPointListener, 100 WifiDialog.WifiDialogListener, DialogInterface.OnDismissListener { 101 102 private static final String TAG = "WifiSettings"; 103 104 private static final int MENU_ID_CONNECT = Menu.FIRST + 6; 105 @VisibleForTesting 106 static final int MENU_ID_FORGET = Menu.FIRST + 7; 107 private static final int MENU_ID_MODIFY = Menu.FIRST + 8; 108 109 public static final int WIFI_DIALOG_ID = 1; 110 111 @VisibleForTesting 112 static final int ADD_NETWORK_REQUEST = 2; 113 114 static final int CONFIG_NETWORK_REQUEST = 3; 115 116 // Instance state keys 117 private static final String SAVE_DIALOG_MODE = "dialog_mode"; 118 private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state"; 119 120 private static final String PREF_KEY_EMPTY_WIFI_LIST = "wifi_empty_list"; 121 private static final String PREF_KEY_CONNECTED_ACCESS_POINTS = "connected_access_point"; 122 private static final String PREF_KEY_ACCESS_POINTS = "access_points"; 123 private static final String PREF_KEY_CONFIGURE_WIFI_SETTINGS = "configure_wifi_settings"; 124 private static final String PREF_KEY_SAVED_NETWORKS = "saved_networks"; 125 private static final String PREF_KEY_STATUS_MESSAGE = "wifi_status_message"; 126 @VisibleForTesting 127 static final String PREF_KEY_DATA_USAGE = "wifi_data_usage"; 128 129 private static final int REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER = 0; 130 isVerboseLoggingEnabled()131 private static boolean isVerboseLoggingEnabled() { 132 return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE); 133 } 134 135 private final Runnable mUpdateAccessPointsRunnable = () -> { 136 updateAccessPointPreferences(); 137 }; 138 private final Runnable mHideProgressBarRunnable = () -> { 139 setProgressBarVisible(false); 140 }; 141 142 @VisibleForTesting 143 WifiManager mWifiManager; 144 @VisibleForTesting 145 ConnectivityManager mConnectivityManager; 146 private WifiManager.ActionListener mConnectListener; 147 private WifiManager.ActionListener mSaveListener; 148 private WifiManager.ActionListener mForgetListener; 149 @VisibleForTesting 150 CaptivePortalNetworkCallback mCaptivePortalNetworkCallback; 151 private Network mLastNetworkCaptivePortalAppStarted; 152 153 /** 154 * The state of {@link #isUiRestricted()} at {@link #onCreate(Bundle)}}. This is neccesary to 155 * ensure that behavior is consistent if {@link #isUiRestricted()} changes. It could be changed 156 * by the Test DPC tool in AFW mode. 157 */ 158 private boolean mIsRestricted; 159 160 private WifiEnabler mWifiEnabler; 161 // An access point being edited is stored here. 162 private AccessPoint mSelectedAccessPoint; 163 164 private WifiDialog mDialog; 165 166 private View mProgressHeader; 167 168 // this boolean extra specifies whether to disable the Next button when not connected. Used by 169 // account creation outside of setup wizard. 170 private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect"; 171 // This string extra specifies a network to open the connect dialog on, so the user can enter 172 // network credentials. This is used by quick settings for secured networks, among other 173 // things. 174 public static final String EXTRA_START_CONNECT_SSID = "wifi_start_connect_ssid"; 175 176 // should Next button only be enabled when we have a connection? 177 private boolean mEnableNextOnConnection; 178 179 // Save the dialog details 180 private int mDialogMode; 181 private AccessPoint mDlgAccessPoint; 182 private Bundle mAccessPointSavedState; 183 184 @VisibleForTesting 185 WifiTracker mWifiTracker; 186 private String mOpenSsid; 187 188 private AccessPointPreference.UserBadgeCache mUserBadgeCache; 189 190 private PreferenceCategory mConnectedAccessPointPreferenceCategory; 191 private PreferenceCategory mAccessPointsPreferenceCategory; 192 @VisibleForTesting 193 AddWifiNetworkPreference mAddWifiNetworkPreference; 194 @VisibleForTesting 195 Preference mConfigureWifiSettingsPreference; 196 @VisibleForTesting 197 Preference mSavedNetworksPreference; 198 @VisibleForTesting 199 DataUsagePreference mDataUsagePreference; 200 private LinkablePreference mStatusMessagePreference; 201 202 /** 203 * Tracks whether the user initiated a connection via clicking in order to autoscroll to the 204 * network once connected. 205 */ 206 private boolean mClickedConnect; 207 @ConnectSource int mConnectSource = CONNECT_SOURCE_UNSPECIFIED; 208 209 private static final int CONNECT_SOURCE_UNSPECIFIED = 0; 210 private static final int CONNECT_SOURCE_NETWORK_MENU_ITEM_CLICK = 1; 211 private static final int CONNECT_SOURCE_NETWORK_LIST_ITEM_CLICK = 2; 212 213 @IntDef({CONNECT_SOURCE_UNSPECIFIED, CONNECT_SOURCE_NETWORK_MENU_ITEM_CLICK, 214 CONNECT_SOURCE_NETWORK_LIST_ITEM_CLICK}) 215 private @interface ConnectSource {} 216 217 /* End of "used in Wifi Setup context" */ 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().setSwitchBarText( 233 R.string.wifi_settings_master_switch_title, 234 R.string.wifi_settings_master_switch_title); 235 } 236 237 @Override onCreate(Bundle icicle)238 public void onCreate(Bundle icicle) { 239 super.onCreate(icicle); 240 241 if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlagUtils.SETTINGS_WIFITRACKER2)) { 242 final Intent intent = new Intent("android.settings.WIFI_SETTINGS2"); 243 final Bundle extras = getActivity().getIntent().getExtras(); 244 if (extras != null) { 245 intent.putExtras(extras); 246 } 247 getContext().startActivity(intent); 248 finish(); 249 return; 250 } 251 252 // TODO(b/37429702): Add animations and preference comparator back after initial screen is 253 // loaded (ODR). 254 setAnimationAllowed(false); 255 256 addPreferences(); 257 258 mIsRestricted = isUiRestricted(); 259 } 260 addPreferences()261 private void addPreferences() { 262 addPreferencesFromResource(R.xml.wifi_settings); 263 264 mConnectedAccessPointPreferenceCategory = 265 (PreferenceCategory) findPreference(PREF_KEY_CONNECTED_ACCESS_POINTS); 266 mAccessPointsPreferenceCategory = 267 (PreferenceCategory) 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 = (LinkablePreference) findPreference(PREF_KEY_STATUS_MESSAGE); 272 mUserBadgeCache = new AccessPointPreference.UserBadgeCache(getPackageManager()); 273 mDataUsagePreference = findPreference(PREF_KEY_DATA_USAGE); 274 mDataUsagePreference.setVisible(DataUsageUtils.hasWifiRadio(getContext())); 275 mDataUsagePreference.setTemplate(NetworkTemplate.buildTemplateWifiWildcard(), 276 0 /*subId*/, 277 null /*service*/); 278 } 279 280 @Override onActivityCreated(Bundle savedInstanceState)281 public void onActivityCreated(Bundle savedInstanceState) { 282 super.onActivityCreated(savedInstanceState); 283 284 mWifiTracker = WifiTrackerFactory.create( 285 getActivity(), this, getSettingsLifecycle(), true, true); 286 mWifiManager = mWifiTracker.getManager(); 287 288 final Activity activity = getActivity(); 289 if (activity != null) { 290 mConnectivityManager = getActivity().getSystemService(ConnectivityManager.class); 291 } 292 293 mConnectListener = new WifiConnectListener(getActivity()); 294 295 mSaveListener = new WifiManager.ActionListener() { 296 @Override 297 public void onSuccess() { 298 } 299 300 @Override 301 public void onFailure(int reason) { 302 Activity activity = getActivity(); 303 if (activity != null) { 304 Toast.makeText(activity, 305 R.string.wifi_failed_save_message, 306 Toast.LENGTH_SHORT).show(); 307 } 308 } 309 }; 310 311 mForgetListener = new WifiManager.ActionListener() { 312 @Override 313 public void onSuccess() { 314 } 315 316 @Override 317 public void onFailure(int reason) { 318 Activity activity = getActivity(); 319 if (activity != null) { 320 Toast.makeText(activity, 321 R.string.wifi_failed_forget_message, 322 Toast.LENGTH_SHORT).show(); 323 } 324 } 325 }; 326 327 if (savedInstanceState != null) { 328 mDialogMode = savedInstanceState.getInt(SAVE_DIALOG_MODE); 329 if (savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) { 330 mAccessPointSavedState = 331 savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE); 332 } 333 } 334 335 // if we're supposed to enable/disable the Next button based on our current connection 336 // state, start it off in the right state 337 Intent intent = getActivity().getIntent(); 338 mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false); 339 340 if (mEnableNextOnConnection) { 341 if (hasNextButton()) { 342 final ConnectivityManager connectivity = (ConnectivityManager) 343 getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); 344 if (connectivity != null) { 345 NetworkInfo info = connectivity.getNetworkInfo( 346 ConnectivityManager.TYPE_WIFI); 347 changeNextButtonState(info.isConnected()); 348 } 349 } 350 } 351 352 registerForContextMenu(getListView()); 353 setHasOptionsMenu(true); 354 355 if (intent.hasExtra(EXTRA_START_CONNECT_SSID)) { 356 mOpenSsid = intent.getStringExtra(EXTRA_START_CONNECT_SSID); 357 } 358 } 359 360 @Override onDestroyView()361 public void onDestroyView() { 362 super.onDestroyView(); 363 364 if (mWifiEnabler != null) { 365 mWifiEnabler.teardownSwitchController(); 366 } 367 } 368 369 @Override onStart()370 public void onStart() { 371 super.onStart(); 372 373 // On/off switch is hidden for Setup Wizard (returns null) 374 mWifiEnabler = createWifiEnabler(); 375 376 if (mIsRestricted) { 377 restrictUi(); 378 return; 379 } 380 381 onWifiStateChanged(mWifiManager.getWifiState()); 382 } 383 restrictUi()384 private void restrictUi() { 385 if (!isUiRestrictedByOnlyAdmin()) { 386 getEmptyTextView().setText(R.string.wifi_empty_list_user_restricted); 387 } 388 getPreferenceScreen().removeAll(); 389 } 390 391 /** 392 * @return new WifiEnabler or null (as overridden by WifiSettingsForSetupWizard) 393 */ createWifiEnabler()394 private WifiEnabler createWifiEnabler() { 395 final SettingsActivity activity = (SettingsActivity) getActivity(); 396 return new WifiEnabler(activity, new SwitchBarController(activity.getSwitchBar()), 397 mMetricsFeatureProvider); 398 } 399 400 @Override onResume()401 public void onResume() { 402 final Activity activity = getActivity(); 403 super.onResume(); 404 405 // Because RestrictedSettingsFragment's onResume potentially requests authorization, 406 // which changes the restriction state, recalculate it. 407 final boolean alreadyImmutablyRestricted = mIsRestricted; 408 mIsRestricted = isUiRestricted(); 409 if (!alreadyImmutablyRestricted && mIsRestricted) { 410 restrictUi(); 411 } 412 413 if (mWifiEnabler != null) { 414 mWifiEnabler.resume(activity); 415 } 416 } 417 418 @Override onPause()419 public void onPause() { 420 super.onPause(); 421 if (mWifiEnabler != null) { 422 mWifiEnabler.pause(); 423 } 424 } 425 426 @Override onStop()427 public void onStop() { 428 getView().removeCallbacks(mUpdateAccessPointsRunnable); 429 getView().removeCallbacks(mHideProgressBarRunnable); 430 unregisterCaptivePortalNetworkCallback(); 431 super.onStop(); 432 } 433 434 @Override onActivityResult(int requestCode, int resultCode, Intent data)435 public void onActivityResult(int requestCode, int resultCode, Intent data) { 436 super.onActivityResult(requestCode, resultCode, data); 437 438 if (requestCode == ADD_NETWORK_REQUEST) { 439 handleAddNetworkRequest(resultCode, data); 440 return; 441 } else if (requestCode == REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER) { 442 if (resultCode == Activity.RESULT_OK) { 443 if (mDialog != null) { 444 mDialog.dismiss(); 445 } 446 mWifiTracker.resumeScanning(); 447 } 448 return; 449 } else if (requestCode == CONFIG_NETWORK_REQUEST) { 450 if (resultCode == Activity.RESULT_OK) { 451 handleConfigNetworkSubmitEvent(data); 452 } 453 return; 454 } 455 456 final boolean formerlyRestricted = mIsRestricted; 457 mIsRestricted = isUiRestricted(); 458 if (formerlyRestricted && !mIsRestricted 459 && getPreferenceScreen().getPreferenceCount() == 0) { 460 // De-restrict the ui 461 addPreferences(); 462 } 463 } 464 465 @Override onCreateAdapter(PreferenceScreen preferenceScreen)466 protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) { 467 final RecyclerView.Adapter adapter = super.onCreateAdapter(preferenceScreen); 468 adapter.setHasStableIds(true); 469 return adapter; 470 } 471 472 @Override getMetricsCategory()473 public int getMetricsCategory() { 474 return SettingsEnums.WIFI; 475 } 476 477 @Override onSaveInstanceState(Bundle outState)478 public void onSaveInstanceState(Bundle outState) { 479 super.onSaveInstanceState(outState); 480 // If dialog has been shown, save its state. 481 if (mDialog != null) { 482 outState.putInt(SAVE_DIALOG_MODE, mDialogMode); 483 if (mDlgAccessPoint != null) { 484 mAccessPointSavedState = new Bundle(); 485 mDlgAccessPoint.saveWifiState(mAccessPointSavedState); 486 outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState); 487 } 488 } 489 } 490 491 @Override onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info)492 public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) { 493 Preference preference = (Preference) view.getTag(); 494 495 if (preference instanceof LongPressAccessPointPreference) { 496 mSelectedAccessPoint = 497 ((LongPressAccessPointPreference) preference).getAccessPoint(); 498 menu.setHeaderTitle(mSelectedAccessPoint.getTitle()); 499 if (mSelectedAccessPoint.isConnectable()) { 500 menu.add(Menu.NONE, MENU_ID_CONNECT, 0 /* order */, R.string.wifi_connect); 501 } 502 503 WifiConfiguration config = mSelectedAccessPoint.getConfig(); 504 // Some configs are ineditable 505 if (WifiUtils.isNetworkLockedDown(getActivity(), config)) { 506 return; 507 } 508 509 // "forget" for normal saved network. And "disconnect" for ephemeral network because it 510 // could only be disconnected and be put in blacklists so it won't be used again. 511 if (mSelectedAccessPoint.isSaved() || mSelectedAccessPoint.isEphemeral()) { 512 final int stringId = mSelectedAccessPoint.isEphemeral() ? 513 R.string.wifi_disconnect_button_text : R.string.forget; 514 menu.add(Menu.NONE, MENU_ID_FORGET, 0 /* order */, stringId); 515 } 516 517 if (mSelectedAccessPoint.isSaved() && !mSelectedAccessPoint.isActive()) { 518 menu.add(Menu.NONE, MENU_ID_MODIFY, 0 /* order */, R.string.wifi_modify); 519 } 520 } 521 } 522 523 @Override onContextItemSelected(MenuItem item)524 public boolean onContextItemSelected(MenuItem item) { 525 if (mSelectedAccessPoint == null) { 526 return super.onContextItemSelected(item); 527 } 528 switch (item.getItemId()) { 529 case MENU_ID_CONNECT: { 530 boolean isSavedNetwork = mSelectedAccessPoint.isSaved(); 531 if (isSavedNetwork) { 532 connect(mSelectedAccessPoint.getConfig(), isSavedNetwork, 533 CONNECT_SOURCE_NETWORK_MENU_ITEM_CLICK); 534 } else if ((mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) || 535 (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE)) { 536 /** Bypass dialog for unsecured networks */ 537 mSelectedAccessPoint.generateOpenNetworkConfig(); 538 connect(mSelectedAccessPoint.getConfig(), isSavedNetwork, 539 CONNECT_SOURCE_NETWORK_MENU_ITEM_CLICK); 540 } else { 541 showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT); 542 } 543 return true; 544 } 545 case MENU_ID_FORGET: { 546 forget(); 547 return true; 548 } 549 case MENU_ID_MODIFY: { 550 showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_MODIFY); 551 return true; 552 } 553 } 554 return super.onContextItemSelected(item); 555 } 556 557 @Override onPreferenceTreeClick(Preference preference)558 public boolean onPreferenceTreeClick(Preference preference) { 559 // If the preference has a fragment set, open that 560 if (preference.getFragment() != null) { 561 preference.setOnPreferenceClickListener(null); 562 return super.onPreferenceTreeClick(preference); 563 } 564 565 if (preference instanceof LongPressAccessPointPreference) { 566 mSelectedAccessPoint = ((LongPressAccessPointPreference) preference).getAccessPoint(); 567 if (mSelectedAccessPoint == null) { 568 return false; 569 } 570 if (mSelectedAccessPoint.isActive()) { 571 return super.onPreferenceTreeClick(preference); 572 } 573 /** 574 * Bypass dialog and connect to unsecured networks, or previously connected saved 575 * networks, or Passpoint provided networks. 576 */ 577 switch (WifiUtils.getConnectingType(mSelectedAccessPoint)) { 578 case WifiUtils.CONNECT_TYPE_OSU_PROVISION: 579 mSelectedAccessPoint.startOsuProvisioning(mConnectListener); 580 mClickedConnect = true; 581 break; 582 583 case WifiUtils.CONNECT_TYPE_OPEN_NETWORK: 584 mSelectedAccessPoint.generateOpenNetworkConfig(); 585 connect(mSelectedAccessPoint.getConfig(), 586 mSelectedAccessPoint.isSaved(), 587 CONNECT_SOURCE_NETWORK_LIST_ITEM_CLICK); 588 break; 589 590 case WifiUtils.CONNECT_TYPE_SAVED_NETWORK: 591 connect(mSelectedAccessPoint.getConfig(), 592 true /* isSavedNetwork */, 593 CONNECT_SOURCE_NETWORK_LIST_ITEM_CLICK); 594 break; 595 596 default: 597 final Bundle bundle = ((LongPressAccessPointPreference) preference).getExtras(); 598 mSelectedAccessPoint.saveWifiState(bundle); 599 launchConfigNewNetworkFragment(mSelectedAccessPoint, 600 WifiConfigUiBase.MODE_CONNECT, bundle); 601 break; 602 } 603 } else if (preference == mAddWifiNetworkPreference) { 604 onAddNetworkPressed(); 605 } else { 606 return super.onPreferenceTreeClick(preference); 607 } 608 return true; 609 } 610 showDialog(AccessPoint accessPoint, int dialogMode)611 private void showDialog(AccessPoint accessPoint, int dialogMode) { 612 if (accessPoint != null) { 613 WifiConfiguration config = accessPoint.getConfig(); 614 if (WifiUtils.isNetworkLockedDown(getActivity(), config) && accessPoint.isActive()) { 615 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(), 616 RestrictedLockUtilsInternal.getDeviceOwner(getActivity())); 617 return; 618 } 619 } 620 621 if (mDialog != null) { 622 removeDialog(WIFI_DIALOG_ID); 623 mDialog = null; 624 } 625 626 // Save the access point and edit mode 627 mDlgAccessPoint = accessPoint; 628 mDialogMode = dialogMode; 629 630 showDialog(WIFI_DIALOG_ID); 631 } 632 633 @Override onCreateDialog(int dialogId)634 public Dialog onCreateDialog(int dialogId) { 635 switch (dialogId) { 636 case WIFI_DIALOG_ID: 637 // modify network 638 if (mDlgAccessPoint == null && mAccessPointSavedState != null) { 639 // restore AP from save state 640 mDlgAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState); 641 // Reset the saved access point data 642 mAccessPointSavedState = null; 643 } 644 mDialog = WifiDialog 645 .createModal(getActivity(), this, mDlgAccessPoint, mDialogMode); 646 mSelectedAccessPoint = mDlgAccessPoint; 647 return mDialog; 648 } 649 return super.onCreateDialog(dialogId); 650 } 651 652 @Override onDialogShowing()653 public void onDialogShowing() { 654 super.onDialogShowing(); 655 setOnDismissListener(this); 656 } 657 658 @Override onDismiss(DialogInterface dialog)659 public void onDismiss(DialogInterface dialog) { 660 // We don't keep any dialog object when dialog was dismissed. 661 mDialog = null; 662 } 663 664 @Override getDialogMetricsCategory(int dialogId)665 public int getDialogMetricsCategory(int dialogId) { 666 switch (dialogId) { 667 case WIFI_DIALOG_ID: 668 return SettingsEnums.DIALOG_WIFI_AP_EDIT; 669 default: 670 return 0; 671 } 672 } 673 674 /** 675 * Called to indicate the list of AccessPoints has been updated and 676 * getAccessPoints should be called to get the latest information. 677 */ 678 @Override onAccessPointsChanged()679 public void onAccessPointsChanged() { 680 Log.d(TAG, "onAccessPointsChanged (WifiTracker) callback initiated"); 681 updateAccessPointsDelayed(); 682 } 683 684 /** 685 * Updates access points from {@link WifiManager#getScanResults()}. Adds a delay to have 686 * progress bar displayed before starting to modify APs. 687 */ updateAccessPointsDelayed()688 private void updateAccessPointsDelayed() { 689 // Safeguard from some delayed event handling 690 if (getActivity() != null && !mIsRestricted && mWifiManager.isWifiEnabled()) { 691 final View view = getView(); 692 final Handler handler = view.getHandler(); 693 if (handler != null && handler.hasCallbacks(mUpdateAccessPointsRunnable)) { 694 return; 695 } 696 setProgressBarVisible(true); 697 view.postDelayed(mUpdateAccessPointsRunnable, 300 /* delay milliseconds */); 698 } 699 } 700 701 /** Called when the state of Wifi has changed. */ 702 @Override onWifiStateChanged(int state)703 public void onWifiStateChanged(int state) { 704 if (mIsRestricted) { 705 return; 706 } 707 708 final int wifiState = mWifiManager.getWifiState(); 709 switch (wifiState) { 710 case WifiManager.WIFI_STATE_ENABLED: 711 updateAccessPointPreferences(); 712 break; 713 714 case WifiManager.WIFI_STATE_ENABLING: 715 removeConnectedAccessPointPreference(); 716 removeAccessPointPreference(); 717 addMessagePreference(R.string.wifi_starting); 718 setProgressBarVisible(true); 719 break; 720 721 case WifiManager.WIFI_STATE_DISABLING: 722 removeConnectedAccessPointPreference(); 723 removeAccessPointPreference(); 724 addMessagePreference(R.string.wifi_stopping); 725 break; 726 727 case WifiManager.WIFI_STATE_DISABLED: 728 setOffMessage(); 729 setAdditionalSettingsSummaries(); 730 setProgressBarVisible(false); 731 mConnectSource = CONNECT_SOURCE_UNSPECIFIED; 732 mClickedConnect = false; 733 break; 734 } 735 } 736 737 /** 738 * Called when the connection state of wifi has changed. 739 */ 740 @Override onConnectedChanged()741 public void onConnectedChanged() { 742 changeNextButtonState(mWifiTracker.isConnected()); 743 } 744 745 /** Helper method to return whether an AccessPoint is disabled due to a wrong password */ isDisabledByWrongPassword(AccessPoint accessPoint)746 private static boolean isDisabledByWrongPassword(AccessPoint accessPoint) { 747 WifiConfiguration config = accessPoint.getConfig(); 748 if (config == null) { 749 return false; 750 } 751 WifiConfiguration.NetworkSelectionStatus networkStatus = 752 config.getNetworkSelectionStatus(); 753 if (networkStatus == null 754 || networkStatus.getNetworkSelectionStatus() == NETWORK_SELECTION_ENABLED) { 755 return false; 756 } 757 int reason = networkStatus.getNetworkSelectionDisableReason(); 758 return WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD == reason; 759 } 760 updateAccessPointPreferences()761 private void updateAccessPointPreferences() { 762 // in case state has changed 763 if (!mWifiManager.isWifiEnabled()) { 764 return; 765 } 766 // AccessPoints are sorted by the WifiTracker 767 final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints(); 768 if (isVerboseLoggingEnabled()) { 769 Log.i(TAG, "updateAccessPoints called for: " + accessPoints); 770 } 771 772 boolean hasAvailableAccessPoints = false; 773 mStatusMessagePreference.setVisible(false); 774 mConnectedAccessPointPreferenceCategory.setVisible(true); 775 mAccessPointsPreferenceCategory.setVisible(true); 776 777 cacheRemoveAllPrefs(mAccessPointsPreferenceCategory); 778 779 int index = 780 configureConnectedAccessPointPreferenceCategory(accessPoints) ? 1 : 0; 781 int numAccessPoints = accessPoints.size(); 782 for (; index < numAccessPoints; index++) { 783 AccessPoint accessPoint = accessPoints.get(index); 784 // Ignore access points that are out of range. 785 if (accessPoint.isReachable()) { 786 String key = accessPoint.getKey(); 787 hasAvailableAccessPoints = true; 788 LongPressAccessPointPreference pref = 789 (LongPressAccessPointPreference) getCachedPreference(key); 790 if (pref != null) { 791 pref.setOrder(index); 792 continue; 793 } 794 LongPressAccessPointPreference preference = 795 createLongPressAccessPointPreference(accessPoint); 796 preference.setKey(key); 797 preference.setOrder(index); 798 if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr()) 799 && (accessPoint.getSecurity() != AccessPoint.SECURITY_NONE && 800 accessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) { 801 if (!accessPoint.isSaved() || isDisabledByWrongPassword(accessPoint)) { 802 onPreferenceTreeClick(preference); 803 mOpenSsid = null; 804 } 805 } 806 mAccessPointsPreferenceCategory.addPreference(preference); 807 accessPoint.setListener(WifiSettings.this); 808 preference.refresh(); 809 } 810 } 811 removeCachedPrefs(mAccessPointsPreferenceCategory); 812 mAddWifiNetworkPreference.setOrder(index); 813 mAccessPointsPreferenceCategory.addPreference(mAddWifiNetworkPreference); 814 setAdditionalSettingsSummaries(); 815 816 if (!hasAvailableAccessPoints) { 817 setProgressBarVisible(true); 818 Preference pref = new Preference(getPrefContext()); 819 pref.setSelectable(false); 820 pref.setSummary(R.string.wifi_empty_list_wifi_on); 821 pref.setOrder(index++); 822 pref.setKey(PREF_KEY_EMPTY_WIFI_LIST); 823 mAccessPointsPreferenceCategory.addPreference(pref); 824 } else { 825 // Continuing showing progress bar for an additional delay to overlap with animation 826 getView().postDelayed(mHideProgressBarRunnable, 1700 /* delay millis */); 827 } 828 } 829 830 @NonNull createLongPressAccessPointPreference( AccessPoint accessPoint)831 private LongPressAccessPointPreference createLongPressAccessPointPreference( 832 AccessPoint accessPoint) { 833 return new LongPressAccessPointPreference(accessPoint, getPrefContext(), mUserBadgeCache, 834 false /* forSavedNetworks */, R.drawable.ic_wifi_signal_0, this); 835 } 836 837 @NonNull 838 @VisibleForTesting createConnectedAccessPointPreference( AccessPoint accessPoint, Context context)839 ConnectedAccessPointPreference createConnectedAccessPointPreference( 840 AccessPoint accessPoint, Context context) { 841 return new ConnectedAccessPointPreference(accessPoint, context, mUserBadgeCache, 842 R.drawable.ic_wifi_signal_0, false /* forSavedNetworks */, this); 843 } 844 845 /** 846 * Configure the ConnectedAccessPointPreferenceCategory and return true if the Category was 847 * shown. 848 */ configureConnectedAccessPointPreferenceCategory( List<AccessPoint> accessPoints)849 private boolean configureConnectedAccessPointPreferenceCategory( 850 List<AccessPoint> accessPoints) { 851 if (accessPoints.size() == 0) { 852 removeConnectedAccessPointPreference(); 853 return false; 854 } 855 856 AccessPoint connectedAp = accessPoints.get(0); 857 if (!connectedAp.isActive()) { 858 removeConnectedAccessPointPreference(); 859 return false; 860 } 861 862 // Is the preference category empty? 863 if (mConnectedAccessPointPreferenceCategory.getPreferenceCount() == 0) { 864 addConnectedAccessPointPreference(connectedAp); 865 return true; 866 } 867 868 // Is the previous currently connected SSID different from the new one? 869 ConnectedAccessPointPreference preference = 870 (ConnectedAccessPointPreference) 871 (mConnectedAccessPointPreferenceCategory.getPreference(0)); 872 // The AccessPoints need to be the same reference to ensure that updates are reflected 873 // in the UI. 874 if (preference.getAccessPoint() != connectedAp) { 875 removeConnectedAccessPointPreference(); 876 addConnectedAccessPointPreference(connectedAp); 877 return true; 878 } 879 880 // Else same AP is connected, simply refresh the connected access point preference 881 // (first and only access point in this category). 882 preference.refresh(); 883 // Update any potential changes to the connected network and ensure that the callback is 884 // registered after an onStop lifecycle event. 885 registerCaptivePortalNetworkCallback(getCurrentWifiNetwork(), preference); 886 return true; 887 } 888 889 /** 890 * Creates a Preference for the given {@link AccessPoint} and adds it to the 891 * {@link #mConnectedAccessPointPreferenceCategory}. 892 */ addConnectedAccessPointPreference(AccessPoint connectedAp)893 private void addConnectedAccessPointPreference(AccessPoint connectedAp) { 894 final ConnectedAccessPointPreference pref = 895 createConnectedAccessPointPreference(connectedAp, getPrefContext()); 896 registerCaptivePortalNetworkCallback(getCurrentWifiNetwork(), pref); 897 898 // Launch details page or captive portal on click. 899 pref.setOnPreferenceClickListener( 900 preference -> { 901 pref.getAccessPoint().saveWifiState(pref.getExtras()); 902 if (mCaptivePortalNetworkCallback != null 903 && mCaptivePortalNetworkCallback.isCaptivePortal()) { 904 startCaptivePortalApp( 905 mCaptivePortalNetworkCallback.getNetwork()); 906 } else { 907 launchNetworkDetailsFragment(pref); 908 } 909 return true; 910 }); 911 912 pref.setOnGearClickListener( 913 preference -> { 914 pref.getAccessPoint().saveWifiState(pref.getExtras()); 915 launchNetworkDetailsFragment(pref); 916 }); 917 918 pref.refresh(); 919 920 mConnectedAccessPointPreferenceCategory.addPreference(pref); 921 mConnectedAccessPointPreferenceCategory.setVisible(true); 922 if (mClickedConnect) { 923 mClickedConnect = false; 924 scrollToPreference(mConnectedAccessPointPreferenceCategory); 925 } 926 } 927 registerCaptivePortalNetworkCallback( Network wifiNetwork, ConnectedAccessPointPreference pref)928 private void registerCaptivePortalNetworkCallback( 929 Network wifiNetwork, ConnectedAccessPointPreference pref) { 930 if (wifiNetwork == null || pref == null) { 931 Log.w(TAG, "Network or Preference were null when registering callback."); 932 return; 933 } 934 935 if (mCaptivePortalNetworkCallback != null 936 && mCaptivePortalNetworkCallback.isSameNetworkAndPreference(wifiNetwork, pref)) { 937 return; 938 } 939 940 unregisterCaptivePortalNetworkCallback(); 941 942 mCaptivePortalNetworkCallback = new CaptivePortalNetworkCallback(wifiNetwork, pref) { 943 @Override 944 public void onCaptivePortalCapabilityChanged() { 945 checkStartCaptivePortalApp(); 946 } 947 }; 948 mConnectivityManager.registerNetworkCallback( 949 new NetworkRequest.Builder() 950 .clearCapabilities() 951 .addTransportType(TRANSPORT_WIFI) 952 .build(), 953 mCaptivePortalNetworkCallback, 954 new Handler(Looper.getMainLooper())); 955 } 956 unregisterCaptivePortalNetworkCallback()957 private void unregisterCaptivePortalNetworkCallback() { 958 if (mCaptivePortalNetworkCallback != null) { 959 try { 960 mConnectivityManager.unregisterNetworkCallback(mCaptivePortalNetworkCallback); 961 } catch (RuntimeException e) { 962 Log.e(TAG, "Unregistering CaptivePortalNetworkCallback failed.", e); 963 } 964 mCaptivePortalNetworkCallback = null; 965 } 966 } 967 launchAddNetworkFragment()968 private void launchAddNetworkFragment() { 969 new SubSettingLauncher(getContext()) 970 .setTitleRes(R.string.wifi_add_network) 971 .setDestination(AddNetworkFragment.class.getName()) 972 .setSourceMetricsCategory(getMetricsCategory()) 973 .setResultListener(this, ADD_NETWORK_REQUEST) 974 .launch(); 975 } 976 launchNetworkDetailsFragment(ConnectedAccessPointPreference pref)977 private void launchNetworkDetailsFragment(ConnectedAccessPointPreference pref) { 978 final AccessPoint accessPoint = pref.getAccessPoint(); 979 final Context context = getContext(); 980 final CharSequence title = 981 FeatureFlagUtils.isEnabled(context, FeatureFlags.WIFI_DETAILS_DATAUSAGE_HEADER) 982 ? accessPoint.getTitle() 983 : context.getText(R.string.pref_title_network_details); 984 985 new SubSettingLauncher(getContext()) 986 .setTitleText(title) 987 .setDestination(WifiNetworkDetailsFragment.class.getName()) 988 .setArguments(pref.getExtras()) 989 .setSourceMetricsCategory(getMetricsCategory()) 990 .launch(); 991 } 992 getCurrentWifiNetwork()993 private Network getCurrentWifiNetwork() { 994 return mWifiManager != null ? mWifiManager.getCurrentNetwork() : null; 995 } 996 997 /** Removes all preferences and hide the {@link #mConnectedAccessPointPreferenceCategory}. */ removeConnectedAccessPointPreference()998 private void removeConnectedAccessPointPreference() { 999 mConnectedAccessPointPreferenceCategory.removeAll(); 1000 mConnectedAccessPointPreferenceCategory.setVisible(false); 1001 unregisterCaptivePortalNetworkCallback(); 1002 } 1003 removeAccessPointPreference()1004 private void removeAccessPointPreference() { 1005 mAccessPointsPreferenceCategory.removeAll(); 1006 mAccessPointsPreferenceCategory.setVisible(false); 1007 } 1008 1009 @VisibleForTesting setAdditionalSettingsSummaries()1010 void setAdditionalSettingsSummaries() { 1011 mConfigureWifiSettingsPreference.setSummary(getString( 1012 isWifiWakeupEnabled() 1013 ? R.string.wifi_configure_settings_preference_summary_wakeup_on 1014 : R.string.wifi_configure_settings_preference_summary_wakeup_off)); 1015 1016 final List<AccessPoint> savedNetworks = 1017 WifiSavedConfigUtils.getAllConfigs(getContext(), mWifiManager); 1018 final int numSavedNetworks = (savedNetworks != null) ? savedNetworks.size() : 0; 1019 mSavedNetworksPreference.setVisible(numSavedNetworks > 0); 1020 if (numSavedNetworks > 0) { 1021 mSavedNetworksPreference.setSummary( 1022 getSavedNetworkSettingsSummaryText(savedNetworks, numSavedNetworks)); 1023 } 1024 } 1025 getSavedNetworkSettingsSummaryText( List<AccessPoint> savedNetworks, int numSavedNetworks)1026 private String getSavedNetworkSettingsSummaryText( 1027 List<AccessPoint> savedNetworks, int numSavedNetworks) { 1028 int numSavedPasspointNetworks = 0; 1029 for (AccessPoint savedNetwork : savedNetworks) { 1030 if (savedNetwork.isPasspointConfig() || savedNetwork.isPasspoint()) { 1031 numSavedPasspointNetworks++; 1032 } 1033 } 1034 final int numSavedNormalNetworks = numSavedNetworks - numSavedPasspointNetworks; 1035 1036 if (numSavedNetworks == numSavedNormalNetworks) { 1037 return getResources().getQuantityString(R.plurals.wifi_saved_access_points_summary, 1038 numSavedNormalNetworks, numSavedNormalNetworks); 1039 } else if (numSavedNetworks == numSavedPasspointNetworks) { 1040 return getResources().getQuantityString( 1041 R.plurals.wifi_saved_passpoint_access_points_summary, 1042 numSavedPasspointNetworks, numSavedPasspointNetworks); 1043 } else { 1044 return getResources().getQuantityString(R.plurals.wifi_saved_all_access_points_summary, 1045 numSavedNetworks, numSavedNetworks); 1046 } 1047 } 1048 isWifiWakeupEnabled()1049 private boolean isWifiWakeupEnabled() { 1050 final Context context = getContext(); 1051 final PowerManager powerManager = context.getSystemService(PowerManager.class); 1052 final ContentResolver contentResolver = context.getContentResolver(); 1053 return mWifiManager.isAutoWakeupEnabled() 1054 && mWifiManager.isScanAlwaysAvailable() 1055 && Settings.Global.getInt(contentResolver, 1056 Settings.Global.AIRPLANE_MODE_ON, 0) == 0 1057 && !powerManager.isPowerSaveMode(); 1058 } 1059 setOffMessage()1060 private void setOffMessage() { 1061 final CharSequence title = getText(R.string.wifi_empty_list_wifi_off); 1062 // Don't use WifiManager.isScanAlwaysAvailable() to check the Wi-Fi scanning mode. Instead, 1063 // read the system settings directly. Because when the device is in Airplane mode, even if 1064 // Wi-Fi scanning mode is on, WifiManager.isScanAlwaysAvailable() still returns "off". 1065 // TODO(b/149421497): Fix this? 1066 final boolean wifiScanningMode = mWifiManager.isScanAlwaysAvailable(); 1067 final CharSequence description = wifiScanningMode ? getText(R.string.wifi_scan_notify_text) 1068 : getText(R.string.wifi_scan_notify_text_scanning_off); 1069 final LinkifyUtils.OnClickListener clickListener = 1070 () -> new SubSettingLauncher(getContext()) 1071 .setDestination(ScanningSettings.class.getName()) 1072 .setTitleRes(R.string.location_scanning_screen_title) 1073 .setSourceMetricsCategory(getMetricsCategory()) 1074 .launch(); 1075 mStatusMessagePreference.setText(title, description, clickListener); 1076 removeConnectedAccessPointPreference(); 1077 removeAccessPointPreference(); 1078 mStatusMessagePreference.setVisible(true); 1079 } 1080 addMessagePreference(int messageId)1081 private void addMessagePreference(int messageId) { 1082 mStatusMessagePreference.setTitle(messageId); 1083 mStatusMessagePreference.setVisible(true); 1084 1085 } 1086 setProgressBarVisible(boolean visible)1087 protected void setProgressBarVisible(boolean visible) { 1088 if (mProgressHeader != null) { 1089 mProgressHeader.setVisibility(visible ? View.VISIBLE : View.GONE); 1090 } 1091 } 1092 1093 /** 1094 * Renames/replaces "Next" button when appropriate. "Next" button usually exists in 1095 * Wifi setup screens, not in usual wifi settings screen. 1096 * 1097 * @param enabled true when the device is connected to a wifi network. 1098 */ changeNextButtonState(boolean enabled)1099 private void changeNextButtonState(boolean enabled) { 1100 if (mEnableNextOnConnection && hasNextButton()) { 1101 getNextButton().setEnabled(enabled); 1102 } 1103 } 1104 1105 @Override onForget(WifiDialog dialog)1106 public void onForget(WifiDialog dialog) { 1107 forget(); 1108 } 1109 1110 @Override onSubmit(WifiDialog dialog)1111 public void onSubmit(WifiDialog dialog) { 1112 if (mDialog != null) { 1113 submit(mDialog.getController()); 1114 } 1115 } 1116 1117 @Override onScan(WifiDialog dialog, String ssid)1118 public void onScan(WifiDialog dialog, String ssid) { 1119 // Launch QR code scanner to join a network. 1120 startActivityForResult(WifiDppUtils.getEnrolleeQrCodeScannerIntent(ssid), 1121 REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER); 1122 } 1123 submit(WifiConfigController configController)1124 /* package */ void submit(WifiConfigController configController) { 1125 1126 final WifiConfiguration config = configController.getConfig(); 1127 1128 if (config == null) { 1129 if (mSelectedAccessPoint != null 1130 && mSelectedAccessPoint.isSaved()) { 1131 connect(mSelectedAccessPoint.getConfig(), 1132 true /* isSavedNetwork */, 1133 CONNECT_SOURCE_UNSPECIFIED); 1134 } 1135 } else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) { 1136 mWifiManager.save(config, mSaveListener); 1137 } else { 1138 mWifiManager.save(config, mSaveListener); 1139 if (mSelectedAccessPoint != null) { // Not an "Add network" 1140 connect(config, false /* isSavedNetwork */, 1141 CONNECT_SOURCE_UNSPECIFIED); 1142 } 1143 } 1144 1145 mWifiTracker.resumeScanning(); 1146 } 1147 forget()1148 /* package */ void forget() { 1149 mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_WIFI_FORGET); 1150 if (!mSelectedAccessPoint.isSaved()) { 1151 if (mSelectedAccessPoint.getNetworkInfo() != null && 1152 mSelectedAccessPoint.getNetworkInfo().getState() != State.DISCONNECTED) { 1153 // Network is active but has no network ID - must be ephemeral. 1154 mWifiManager.disableEphemeralNetwork( 1155 AccessPoint.convertToQuotedString(mSelectedAccessPoint.getSsidStr())); 1156 } else { 1157 // Should not happen, but a monkey seems to trigger it 1158 Log.e(TAG, "Failed to forget invalid network " + mSelectedAccessPoint.getConfig()); 1159 return; 1160 } 1161 } else if (mSelectedAccessPoint.getConfig().isPasspoint()) { 1162 try { 1163 mWifiManager.removePasspointConfiguration(mSelectedAccessPoint.getConfig().FQDN); 1164 } catch (IllegalArgumentException e) { 1165 Log.e(TAG, "Failed to remove Passpoint configuration with error: " + e); 1166 return; 1167 } 1168 } else { 1169 mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId, mForgetListener); 1170 } 1171 1172 mWifiTracker.resumeScanning(); 1173 1174 // We need to rename/replace "Next" button in wifi setup context. 1175 changeNextButtonState(false); 1176 } 1177 connect(final WifiConfiguration config, boolean isSavedNetwork, @ConnectSource int connectSource)1178 protected void connect(final WifiConfiguration config, 1179 boolean isSavedNetwork, @ConnectSource int connectSource) { 1180 // Log subtype if configuration is a saved network. 1181 mMetricsFeatureProvider.action(getContext(), SettingsEnums.ACTION_WIFI_CONNECT, 1182 isSavedNetwork); 1183 mConnectSource = connectSource; 1184 mWifiManager.connect(config, mConnectListener); 1185 mClickedConnect = true; 1186 } 1187 1188 @VisibleForTesting handleAddNetworkRequest(int result, Intent data)1189 void handleAddNetworkRequest(int result, Intent data) { 1190 if (result == Activity.RESULT_OK) { 1191 handleAddNetworkSubmitEvent(data); 1192 } 1193 mWifiTracker.resumeScanning(); 1194 } 1195 handleAddNetworkSubmitEvent(Intent data)1196 private void handleAddNetworkSubmitEvent(Intent data) { 1197 final WifiConfiguration wifiConfiguration = data.getParcelableExtra( 1198 AddNetworkFragment.WIFI_CONFIG_KEY); 1199 if (wifiConfiguration != null) { 1200 mWifiManager.save(wifiConfiguration, mSaveListener); 1201 } 1202 } 1203 1204 /** 1205 * Called when "add network" button is pressed. 1206 */ onAddNetworkPressed()1207 private void onAddNetworkPressed() { 1208 // No exact access point is selected. 1209 mSelectedAccessPoint = null; 1210 launchAddNetworkFragment(); 1211 } 1212 1213 @Override getHelpResource()1214 public int getHelpResource() { 1215 return R.string.help_url_wifi; 1216 } 1217 1218 @Override onAccessPointChanged(final AccessPoint accessPoint)1219 public void onAccessPointChanged(final AccessPoint accessPoint) { 1220 Log.d(TAG, "onAccessPointChanged (singular) callback initiated"); 1221 View view = getView(); 1222 if (view != null) { 1223 view.post(new Runnable() { 1224 @Override 1225 public void run() { 1226 Object tag = accessPoint.getTag(); 1227 if (tag != null) { 1228 ((AccessPointPreference) tag).refresh(); 1229 } 1230 } 1231 }); 1232 } 1233 } 1234 1235 @Override onLevelChanged(AccessPoint accessPoint)1236 public void onLevelChanged(AccessPoint accessPoint) { 1237 ((AccessPointPreference) accessPoint.getTag()).onLevelChanged(); 1238 } 1239 handleConfigNetworkSubmitEvent(Intent data)1240 private void handleConfigNetworkSubmitEvent(Intent data) { 1241 final WifiConfiguration wifiConfiguration = data.getParcelableExtra( 1242 ConfigureAccessPointFragment.NETWORK_CONFIG_KEY); 1243 if (wifiConfiguration != null) { 1244 mWifiManager.save(wifiConfiguration, mSaveListener); 1245 1246 if (mSelectedAccessPoint != null) { 1247 connect(wifiConfiguration, false /*isSavedNetwork*/, 1248 CONNECT_SOURCE_UNSPECIFIED); 1249 } 1250 mWifiTracker.resumeScanning(); 1251 } 1252 } 1253 launchConfigNewNetworkFragment(AccessPoint accessPoint, int dialogMode, Bundle bundleForArguments)1254 private void launchConfigNewNetworkFragment(AccessPoint accessPoint, int dialogMode, 1255 Bundle bundleForArguments) { 1256 mDialogMode = dialogMode; 1257 final CharSequence title = accessPoint.getTitle(); 1258 new SubSettingLauncher(getContext()) 1259 .setTitleText(title) 1260 .setDestination(ConfigureAccessPointFragment.class.getName()) 1261 .setArguments(bundleForArguments) 1262 .setSourceMetricsCategory(getMetricsCategory()) 1263 .setResultListener(this, CONFIG_NETWORK_REQUEST) 1264 .launch(); 1265 } 1266 1267 /** 1268 * Starts the captive portal for current network if it's been clicked from the available 1269 * networks (or contextual menu). We only do it *once* for a picked network, to avoid connecting 1270 * again on bg/fg or if user dismisses Captive Portal before connecting (otherwise, coming back 1271 * to this screen while connected to the same network but not signed in would open CP again). 1272 */ checkStartCaptivePortalApp()1273 private void checkStartCaptivePortalApp() { 1274 Network currentNetwork = getCurrentWifiNetwork(); 1275 if (mCaptivePortalNetworkCallback == null || currentNetwork == null 1276 || !currentNetwork.equals(mCaptivePortalNetworkCallback.getNetwork()) 1277 || !mCaptivePortalNetworkCallback.isCaptivePortal()) { 1278 return; 1279 } 1280 1281 if (mConnectSource != CONNECT_SOURCE_NETWORK_LIST_ITEM_CLICK 1282 && mConnectSource != CONNECT_SOURCE_NETWORK_MENU_ITEM_CLICK) { 1283 return; 1284 } 1285 1286 if (mLastNetworkCaptivePortalAppStarted != null 1287 && mLastNetworkCaptivePortalAppStarted.equals(currentNetwork)) { 1288 // We already auto-opened CP for same network 1289 return; 1290 } 1291 1292 startCaptivePortalApp(currentNetwork); 1293 } 1294 startCaptivePortalApp(Network network)1295 private void startCaptivePortalApp(Network network) { 1296 if (mConnectivityManager == null || network == null) { 1297 return; 1298 } 1299 mLastNetworkCaptivePortalAppStarted = network; 1300 mConnectivityManager.startCaptivePortalApp(network); 1301 } 1302 1303 public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 1304 new BaseSearchIndexProvider(R.xml.wifi_settings) { 1305 @Override 1306 public List<String> getNonIndexableKeys(Context context) { 1307 final List<String> keys = super.getNonIndexableKeys(context); 1308 1309 final WifiManager wifiManager = context.getSystemService(WifiManager.class); 1310 if (WifiSavedConfigUtils.getAllConfigsCount(context, wifiManager) == 0) { 1311 keys.add(PREF_KEY_SAVED_NETWORKS); 1312 } 1313 1314 if (!DataUsageUtils.hasWifiRadio(context)) { 1315 keys.add(PREF_KEY_DATA_USAGE); 1316 } 1317 return keys; 1318 } 1319 }; 1320 } 1321