1 /* 2 * Copyright (C) 2016 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.tv.settings.connectivity; 18 19 import static com.android.tv.settings.overlay.FlavorUtils.FLAVOR_CLASSIC; 20 import static com.android.tv.settings.overlay.FlavorUtils.FLAVOR_TWO_PANEL; 21 import static com.android.tv.settings.overlay.FlavorUtils.FLAVOR_VENDOR; 22 import static com.android.tv.settings.overlay.FlavorUtils.FLAVOR_X; 23 import static com.android.tv.settings.util.InstrumentationUtils.logEntrySelected; 24 import static com.android.tv.settings.util.InstrumentationUtils.logToggleInteracted; 25 26 import android.app.tvsettings.TvSettingsEnums; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.pm.PackageManager; 30 import android.content.pm.ResolveInfo; 31 import android.net.ConnectivityManager; 32 import android.net.NetworkCapabilities; 33 import android.net.NetworkInfo; 34 import android.net.wifi.WifiConfiguration; 35 import android.net.wifi.WifiManager; 36 import android.os.Bundle; 37 import android.os.Handler; 38 import android.os.SystemClock; 39 import android.os.UserManager; 40 import android.provider.Settings; 41 42 import androidx.annotation.Keep; 43 import androidx.preference.Preference; 44 import androidx.preference.PreferenceCategory; 45 import androidx.preference.PreferenceManager; 46 import androidx.preference.TwoStatePreference; 47 48 import com.android.settingslib.RestrictedPreference; 49 import com.android.settingslib.wifi.AccessPoint; 50 import com.android.tv.settings.MainFragment; 51 import com.android.tv.settings.R; 52 import com.android.tv.settings.RestrictedPreferenceAdapter; 53 import com.android.tv.settings.SettingsPreferenceFragment; 54 import com.android.tv.settings.overlay.FlavorUtils; 55 import com.android.tv.settings.util.SliceUtils; 56 import com.android.tv.settings.widget.CustomContentDescriptionSwitchPreference; 57 import com.android.tv.settings.widget.TvAccessPointPreference; 58 import com.android.tv.twopanelsettings.slices.SlicePreference; 59 60 import java.util.Collection; 61 import java.util.HashSet; 62 import java.util.Set; 63 64 /** 65 * Fragment for controlling network connectivity 66 */ 67 @Keep 68 public class NetworkFragment extends SettingsPreferenceFragment implements 69 ConnectivityListener.Listener, ConnectivityListener.WifiNetworkListener, 70 AccessPoint.AccessPointListener { 71 72 private static final String KEY_WIFI_ENABLE = "wifi_enable"; 73 private static final String KEY_WIFI_LIST = "wifi_list"; 74 private static final String KEY_WIFI_COLLAPSE = "wifi_collapse"; 75 private static final String KEY_WIFI_OTHER = "wifi_other"; 76 private static final String KEY_WIFI_ADD = "wifi_add"; 77 private static final String KEY_WIFI_ADD_EASYCONNECT = "wifi_add_easyconnect"; 78 private static final String KEY_WIFI_ALWAYS_SCAN = "wifi_always_scan"; 79 private static final String KEY_ETHERNET = "ethernet"; 80 private static final String KEY_ETHERNET_STATUS = "ethernet_status"; 81 private static final String KEY_ETHERNET_PROXY = "ethernet_proxy"; 82 private static final String KEY_ETHERNET_DHCP = "ethernet_dhcp"; 83 private static final String KEY_DATA_SAVER_SLICE = "data_saver_slice"; 84 private static final String KEY_DATA_ALERT_SLICE = "data_alert_slice"; 85 private static final String KEY_NETWORK_DIAGNOSTICS = "network_diagnostics"; 86 87 private static final String ACTION_DATA_ALERT_SETTINGS = "android.settings.DATA_ALERT_SETTINGS"; 88 private static final int INITIAL_UPDATE_DELAY = 500; 89 90 private static final String NETWORK_DIAGNOSTICS_ACTION = 91 "com.android.tv.settings.network.NETWORK_DIAGNOSTICS"; 92 93 private ConnectivityListener mConnectivityListener; 94 private WifiManager mWifiManager; 95 private ConnectivityManager mConnectivityManager; 96 private TvAccessPointPreference.UserBadgeCache mUserBadgeCache; 97 98 private TwoStatePreference mEnableWifiPref; 99 private CollapsibleCategory mWifiNetworksCategory; 100 private Preference mCollapsePref; 101 private RestrictedPreference mAddPref; 102 private RestrictedPreference mAddEasyConnectPref; 103 private TwoStatePreference mAlwaysScan; 104 private PreferenceCategory mEthernetCategory; 105 private Preference mEthernetStatusPref; 106 private Preference mEthernetProxyPref; 107 private Preference mEthernetDhcpPref; 108 private PreferenceCategory mWifiOther; 109 110 private final Handler mHandler = new Handler(); 111 private long mNoWifiUpdateBeforeMillis; 112 private Runnable mInitialUpdateWifiListRunnable = new Runnable() { 113 @Override 114 public void run() { 115 mNoWifiUpdateBeforeMillis = 0; 116 updateWifiList(); 117 } 118 }; 119 private boolean mIsWifiHardwarePresent; 120 newInstance()121 public static NetworkFragment newInstance() { 122 return new NetworkFragment(); 123 } 124 125 @Override onCreate(Bundle savedInstanceState)126 public void onCreate(Bundle savedInstanceState) { 127 mIsWifiHardwarePresent = getContext().getPackageManager() 128 .hasSystemFeature(PackageManager.FEATURE_WIFI); 129 mConnectivityListener = new ConnectivityListener( 130 getContext(), this, getSettingsLifecycle()); 131 mWifiManager = getContext().getSystemService(WifiManager.class); 132 mConnectivityManager = getContext().getSystemService(ConnectivityManager.class); 133 mUserBadgeCache = 134 new TvAccessPointPreference.UserBadgeCache(getContext().getPackageManager()); 135 super.onCreate(savedInstanceState); 136 } 137 138 @Override onStart()139 public void onStart() { 140 super.onStart(); 141 mConnectivityListener.setWifiListener(this); 142 mNoWifiUpdateBeforeMillis = SystemClock.elapsedRealtime() + INITIAL_UPDATE_DELAY; 143 updateWifiList(); 144 } 145 146 @Override onDestroy()147 public void onDestroy() { 148 super.onDestroy(); 149 } 150 151 @Override onResume()152 public void onResume() { 153 super.onResume(); 154 // There doesn't seem to be an API to listen to everything this could cover, so 155 // tickle it here and hope for the best. 156 updateConnectivity(); 157 } 158 getPreferenceScreenResId()159 private int getPreferenceScreenResId() { 160 switch (FlavorUtils.getFlavor(getContext())) { 161 case FLAVOR_CLASSIC: 162 case FLAVOR_TWO_PANEL: 163 return R.xml.network; 164 case FLAVOR_X: 165 case FLAVOR_VENDOR: 166 return R.xml.network_x; 167 default: 168 return R.xml.network; 169 } 170 } 171 172 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)173 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 174 getPreferenceManager().setPreferenceComparisonCallback( 175 new PreferenceManager.SimplePreferenceComparisonCallback()); 176 setPreferencesFromResource(getPreferenceScreenResId(), null); 177 178 mEnableWifiPref = (TwoStatePreference) findPreference(KEY_WIFI_ENABLE); 179 mWifiNetworksCategory = (CollapsibleCategory) findPreference(KEY_WIFI_LIST); 180 mCollapsePref = findPreference(KEY_WIFI_COLLAPSE); 181 mAddPref = (RestrictedPreference) findPreference(KEY_WIFI_ADD); 182 mAddEasyConnectPref = (RestrictedPreference) findPreference(KEY_WIFI_ADD_EASYCONNECT); 183 mAlwaysScan = (TwoStatePreference) findPreference(KEY_WIFI_ALWAYS_SCAN); 184 mWifiOther = (PreferenceCategory) findPreference(KEY_WIFI_OTHER); 185 186 mEthernetCategory = (PreferenceCategory) findPreference(KEY_ETHERNET); 187 mEthernetStatusPref = findPreference(KEY_ETHERNET_STATUS); 188 mEthernetProxyPref = findPreference(KEY_ETHERNET_PROXY); 189 mEthernetProxyPref.setIntent(EditProxySettingsActivity.createIntent(getContext(), 190 WifiConfiguration.INVALID_NETWORK_ID)); 191 mEthernetDhcpPref = findPreference(KEY_ETHERNET_DHCP); 192 mEthernetDhcpPref.setIntent(EditIpSettingsActivity.createIntent(getContext(), 193 WifiConfiguration.INVALID_NETWORK_ID)); 194 195 if (!mIsWifiHardwarePresent) { 196 mEnableWifiPref.setVisible(false); 197 } 198 199 updateVisibilityForDataSaver(); 200 Preference dataSaverSlicePref = findPreference(KEY_DATA_SAVER_SLICE); 201 Preference dataAlertSlicePref = findPreference(KEY_DATA_ALERT_SLICE); 202 Intent i = getActivity().getIntent(); 203 if (i != null && i.getAction() != null) { 204 if (i.getAction().equals(Settings.ACTION_DATA_SAVER_SETTINGS) 205 && dataSaverSlicePref.isVisible()) { 206 mHandler.post(() -> scrollToPreference(dataSaverSlicePref)); 207 } else if (i.getAction().equals(ACTION_DATA_ALERT_SETTINGS) 208 && dataAlertSlicePref.isVisible()) { 209 mHandler.post(() -> scrollToPreference(dataAlertSlicePref)); 210 } 211 } 212 213 Preference networkDiagnosticsPref = findPreference(KEY_NETWORK_DIAGNOSTICS); 214 Intent networkDiagnosticsIntent = makeNetworkDiagnosticsIntent(); 215 if (networkDiagnosticsIntent != null) { 216 networkDiagnosticsPref.setVisible(true); 217 networkDiagnosticsPref.setIntent(networkDiagnosticsIntent); 218 } else { 219 networkDiagnosticsPref.setVisible(false); 220 } 221 222 final UserManager userManager = UserManager.get(getContext()); 223 if (userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) { 224 mAddPref.setFragment(null); 225 mAddEasyConnectPref.setFragment(null); 226 227 if (!mAddPref.isDisabledByAdmin()) { 228 mAddPref.setEnabled(false); 229 } 230 if (!mAddEasyConnectPref.isDisabledByAdmin()) { 231 mAddEasyConnectPref.setEnabled(false); 232 } 233 } 234 } 235 updateVisibilityForDataSaver()236 private void updateVisibilityForDataSaver() { 237 Preference dataSaverSlicePref = findPreference(KEY_DATA_SAVER_SLICE); 238 Preference dataAlertSlicePref = findPreference(KEY_DATA_ALERT_SLICE); 239 boolean isDataSaverVisible = isConnected() && SliceUtils.isSliceProviderValid( 240 getContext(), ((SlicePreference) dataSaverSlicePref).getUri()); 241 boolean isDataAlertVisible = isConnected() && SliceUtils.isSliceProviderValid( 242 getContext(), ((SlicePreference) dataAlertSlicePref).getUri()); 243 dataSaverSlicePref.setVisible(isDataSaverVisible); 244 dataAlertSlicePref.setVisible(isDataAlertVisible); 245 } 246 247 @Override onPreferenceTreeClick(Preference preference)248 public boolean onPreferenceTreeClick(Preference preference) { 249 if (preference.getKey() == null) { 250 return super.onPreferenceTreeClick(preference); 251 } 252 switch (preference.getKey()) { 253 case KEY_WIFI_ENABLE: 254 mConnectivityListener.setWifiEnabled(mEnableWifiPref.isChecked()); 255 logToggleInteracted( 256 TvSettingsEnums.NETWORK_WIFI_ON_OFF, mEnableWifiPref.isChecked()); 257 return true; 258 case KEY_WIFI_COLLAPSE: 259 final boolean collapse = !mWifiNetworksCategory.isCollapsed(); 260 mCollapsePref.setTitle(collapse 261 ? R.string.wifi_setting_see_all : R.string.wifi_setting_see_fewer); 262 mWifiNetworksCategory.setCollapsed(collapse); 263 logEntrySelected( 264 collapse 265 ? TvSettingsEnums.NETWORK_SEE_FEWER 266 : TvSettingsEnums.NETWORK_SEE_ALL); 267 return true; 268 case KEY_WIFI_ALWAYS_SCAN: 269 Settings.Global.putInt(getActivity().getContentResolver(), 270 Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 271 mAlwaysScan.isChecked() ? 1 : 0); 272 logToggleInteracted( 273 TvSettingsEnums.NETWORK_ALWAYS_SCANNING_NETWORKS, mAlwaysScan.isChecked()); 274 return true; 275 case KEY_ETHERNET_STATUS: 276 return true; 277 case KEY_WIFI_ADD: 278 logEntrySelected(TvSettingsEnums.NETWORK_ADD_NEW_NETWORK); 279 break; 280 case KEY_WIFI_ADD_EASYCONNECT: 281 startActivity(AddWifiNetworkActivity.createEasyConnectIntent(getContext())); 282 break; 283 } 284 return super.onPreferenceTreeClick(preference); 285 } 286 isConnected()287 private boolean isConnected() { 288 NetworkInfo activeNetworkInfo = mConnectivityManager.getActiveNetworkInfo(); 289 return activeNetworkInfo != null && activeNetworkInfo.isConnected() 290 && ConnectivityManager.TYPE_ETHERNET != activeNetworkInfo.getType(); 291 } 292 updateConnectivity()293 private void updateConnectivity() { 294 if (!isAdded()) { 295 return; 296 } 297 298 final boolean wifiEnabled = mIsWifiHardwarePresent 299 && mConnectivityListener.isWifiEnabledOrEnabling(); 300 mEnableWifiPref.setChecked(wifiEnabled); 301 302 mWifiNetworksCategory.setVisible(wifiEnabled); 303 mCollapsePref.setVisible(wifiEnabled && mWifiNetworksCategory.shouldShowCollapsePref()); 304 mAddPref.setVisible(wifiEnabled); 305 if (mAddEasyConnectPref != null) { 306 mAddEasyConnectPref.setVisible(wifiEnabled && mWifiManager.isEasyConnectSupported()); 307 } 308 309 if (!wifiEnabled) { 310 updateWifiList(); 311 } 312 313 int scanAlwaysAvailable = 0; 314 try { 315 scanAlwaysAvailable = Settings.Global.getInt(getContext().getContentResolver(), 316 Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE); 317 } catch (Settings.SettingNotFoundException e) { 318 // Ignore 319 } 320 mAlwaysScan.setChecked(scanAlwaysAvailable == 1); 321 if (mAlwaysScan instanceof CustomContentDescriptionSwitchPreference) { 322 ((CustomContentDescriptionSwitchPreference) mAlwaysScan).setContentDescription( 323 getResources() 324 .getString( 325 R.string.wifi_setting_always_scan_content_description)); 326 } 327 328 final boolean ethernetAvailable = mConnectivityListener.isEthernetAvailable(); 329 mEthernetCategory.setVisible(ethernetAvailable); 330 mEthernetStatusPref.setVisible(ethernetAvailable); 331 mEthernetProxyPref.setVisible(ethernetAvailable); 332 mEthernetProxyPref.setOnPreferenceClickListener( 333 preference -> { 334 logEntrySelected(TvSettingsEnums.NETWORK_ETHERNET_PROXY_SETTINGS); 335 return false; 336 }); 337 mEthernetDhcpPref.setVisible(ethernetAvailable); 338 mEthernetDhcpPref.setOnPreferenceClickListener( 339 preference -> { 340 logEntrySelected(TvSettingsEnums.NETWORK_ETHERNET_IP_SETTINGS); 341 return false; 342 }); 343 344 if (ethernetAvailable) { 345 final boolean ethernetConnected = 346 mConnectivityListener.isEthernetConnected(); 347 mEthernetStatusPref.setTitle(ethernetConnected 348 ? R.string.connected : R.string.not_connected); 349 mEthernetStatusPref.setSummary(mConnectivityListener.getEthernetIpAddress()); 350 } 351 352 updateVisibilityForDataSaver(); 353 } 354 updateWifiList()355 private void updateWifiList() { 356 if (!isAdded()) { 357 return; 358 } 359 360 if (!mIsWifiHardwarePresent || !mConnectivityListener.isWifiEnabledOrEnabling()) { 361 mWifiNetworksCategory.removeAll(); 362 mNoWifiUpdateBeforeMillis = 0; 363 return; 364 } 365 366 final long now = SystemClock.elapsedRealtime(); 367 if (mNoWifiUpdateBeforeMillis > now) { 368 mHandler.removeCallbacks(mInitialUpdateWifiListRunnable); 369 mHandler.postDelayed(mInitialUpdateWifiListRunnable, 370 mNoWifiUpdateBeforeMillis - now); 371 return; 372 } 373 374 final int existingCount = mWifiNetworksCategory.getRealPreferenceCount(); 375 final Set<Preference> toRemove = new HashSet<>(existingCount); 376 for (int i = 0; i < existingCount; i++) { 377 toRemove.add(mWifiNetworksCategory.getPreference(i)); 378 } 379 380 final Context themedContext = getPreferenceManager().getContext(); 381 final Collection<AccessPoint> accessPoints = mConnectivityListener.getAvailableNetworks(); 382 int index = 0; 383 384 for (final AccessPoint accessPoint : accessPoints) { 385 accessPoint.setListener(this); 386 RestrictedPreferenceAdapter<TvAccessPointPreference> restrictedPref = 387 (RestrictedPreferenceAdapter<TvAccessPointPreference>) accessPoint.getTag(); 388 Preference pref; 389 if (restrictedPref == null) { 390 pref = new TvAccessPointPreference(accessPoint, themedContext, mUserBadgeCache, 391 false); 392 restrictedPref = new RestrictedPreferenceAdapter(themedContext, pref, 393 UserManager.DISALLOW_CONFIG_WIFI); 394 accessPoint.setTag(restrictedPref); 395 } else { 396 toRemove.remove(restrictedPref.getPreference()); 397 pref = restrictedPref.getOriginalPreference(); 398 } 399 if (accessPoint.isActive() && !isCaptivePortal(accessPoint)) { 400 pref.setFragment(WifiDetailsFragment.class.getName()); 401 // No need to track entry selection as new page will be focused 402 pref.setOnPreferenceClickListener(preference -> false); 403 WifiDetailsFragment.prepareArgs(pref.getExtras(), accessPoint); 404 pref.setIntent(null); 405 } else { 406 pref.setFragment(null); 407 pref.setIntent(WifiConnectionActivity.createIntent(getContext(), accessPoint)); 408 pref.setOnPreferenceClickListener( 409 preference -> { 410 logEntrySelected(TvSettingsEnums.NETWORK_NOT_CONNECTED_AP); 411 return false; 412 }); 413 } 414 pref.setVisible(!restrictedPref.isRestricted() || accessPoint.isSaved()); 415 pref.setOrder(index++); 416 restrictedPref.updatePreference(); 417 418 // Double-adding is harmless 419 mWifiNetworksCategory.addPreference(restrictedPref.getPreference()); 420 } 421 422 for (final Preference preference : toRemove) { 423 mWifiNetworksCategory.removePreference(preference); 424 } 425 426 mCollapsePref.setVisible(mWifiNetworksCategory.shouldShowCollapsePref()); 427 } 428 isCaptivePortal(AccessPoint accessPoint)429 private boolean isCaptivePortal(AccessPoint accessPoint) { 430 if (accessPoint.getDetailedState() != NetworkInfo.DetailedState.CONNECTED) { 431 return false; 432 } 433 NetworkCapabilities nc = mConnectivityManager.getNetworkCapabilities( 434 mWifiManager.getCurrentNetwork()); 435 return nc != null && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL); 436 } 437 makeNetworkDiagnosticsIntent()438 private Intent makeNetworkDiagnosticsIntent() { 439 Intent intent = new Intent(); 440 intent.setAction(NETWORK_DIAGNOSTICS_ACTION); 441 442 ResolveInfo resolveInfo = MainFragment.systemIntentIsHandled(getContext(), intent); 443 if (resolveInfo == null || resolveInfo.activityInfo == null) { 444 return null; 445 } 446 447 intent.setPackage(resolveInfo.activityInfo.packageName); 448 449 return intent; 450 } 451 452 @Override onConnectivityChange()453 public void onConnectivityChange() { 454 updateConnectivity(); 455 } 456 457 @Override onWifiListChanged()458 public void onWifiListChanged() { 459 updateWifiList(); 460 } 461 462 @Override onAccessPointChanged(AccessPoint accessPoint)463 public void onAccessPointChanged(AccessPoint accessPoint) { 464 RestrictedPreferenceAdapter<TvAccessPointPreference> restrictedPref = 465 (RestrictedPreferenceAdapter<TvAccessPointPreference>) accessPoint.getTag(); 466 restrictedPref.updatePreference(pref -> pref.refresh()); 467 } 468 469 @Override onLevelChanged(AccessPoint accessPoint)470 public void onLevelChanged(AccessPoint accessPoint) { 471 RestrictedPreferenceAdapter<TvAccessPointPreference> restrictedPref = 472 (RestrictedPreferenceAdapter<TvAccessPointPreference>) accessPoint.getTag(); 473 restrictedPref.updatePreference(pref -> pref.onLevelChanged()); 474 } 475 476 @Override getPageId()477 protected int getPageId() { 478 return TvSettingsEnums.NETWORK; 479 } 480 } 481