From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Pratyush Date: Wed, 20 Oct 2021 05:40:11 +0530 Subject: [PATCH] add toggle to set captiveportal settings Access is disallowed for users that are disallowed from configuring Private DNS settings. This restriction provides administrative control over this feature in a way that's compatible with existing device manager implementations. Private DNS is the closest fit from the existing user management restrictions that are available. Co-authored-by: stuux Co-authored-by: Renlord Co-authored-by: Danny Lin Co-authored-by: anupritaisno1 Signed-off-by: empratyush [tad@spotco.us]: add multiple other server options [tad@spotco.us]: merge with the GrapheneOS patch from RQ3A.211001.001.2021100606 Change-Id: I8a762d0f29ac42fce3dcfc7189e8ff216a8f8d1a --- res/values/arrays.xml | 30 ++ res/values/strings.xml | 3 + res/xml/network_and_internet.xml | 8 + ...ConnectivityCheckPreferenceController.java | 399 ++++++++++++++++++ .../network/NetworkDashboardFragment.java | 3 + 5 files changed, 443 insertions(+) create mode 100644 src/com/android/settings/network/ConnectivityCheckPreferenceController.java diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 617548cadcb..e1976fb5cf0 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -110,6 +110,36 @@ @string/dark_ui_auto_mode_auto + + Disabled + Amazon Fire OS (US) + Cloudflare (US) + DivestOS (US) + Google (US) [default] + Huawei (CN) + Kuketz (DE) + Microsoft Edge (US) + openSUSE (DE) + Ubuntu (UK) + + + + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index a7a338ed7a2..8d8e7aaccdd 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12237,4 +12237,7 @@ Don\u2019t connect Connect + + Internet connectivity check + HTTP endpoints to use for performing internet connectivity checks. diff --git a/res/xml/network_and_internet.xml b/res/xml/network_and_internet.xml index 6bf6dbaccf7..8ee092aa044 100644 --- a/res/xml/network_and_internet.xml +++ b/res/xml/network_and_internet.xml @@ -125,4 +125,12 @@ android:summary="@string/summary_placeholder" android:order="25" settings:controller="com.android.settings.network.AdaptiveConnectivityPreferenceController"/> + + diff --git a/src/com/android/settings/network/ConnectivityCheckPreferenceController.java b/src/com/android/settings/network/ConnectivityCheckPreferenceController.java new file mode 100644 index 00000000000..9b6e9bb93b1 --- /dev/null +++ b/src/com/android/settings/network/ConnectivityCheckPreferenceController.java @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources; +import android.database.ContentObserver; +import android.net.LinkProperties; +import android.net.Network; +import android.os.Handler; +import android.os.Looper; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; +import androidx.preference.ListPreference; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import com.android.internal.util.ArrayUtils; +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; +import com.android.settingslib.RestrictedLockUtilsInternal; +import com.android.settingslib.core.lifecycle.events.OnResume; + +public class ConnectivityCheckPreferenceController + extends BasePreferenceController + implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener, + OnResume { + + // imported defaults from AOSP NetworkStack + private static final String STANDARD_HTTPS_URL = + "https://www.google.com/generate_204"; + private static final String STANDARD_HTTP_URL = + "http://connectivitycheck.gstatic.com/generate_204"; + private static final String STANDARD_FALLBACK_URL = + "http://www.google.com/gen_204"; + private static final String STANDARD_OTHER_FALLBACK_URLS = + "http://play.googleapis.com/generate_204"; + + // GrapheneOS + private static final String GRAPHENEOS_CAPTIVE_PORTAL_HTTPS_URL = + "https://connectivitycheck.grapheneos.network/generate_204"; + private static final String GRAPHENEOS_CAPTIVE_PORTAL_HTTP_URL = + "http://connectivitycheck.grapheneos.network/generate_204"; + private static final String GRAPHENEOS_CAPTIVE_PORTAL_FALLBACK_URL = + "http://grapheneos.online/gen_204"; + private static final String GRAPHENEOS_CAPTIVE_PORTAL_OTHER_FALLBACK_URL = + "http://grapheneos.online/generate_204"; + + // DivestOS + private static final String DIVESTOS_HTTPS_URL = + "https://divestos.org/generate_204"; + private static final String DIVESTOS_HTTP_URL = + "http://divestos.org/generate_204"; + + // openSUSE + private static final String OPENSUSE_HTTPS_URL = + "https://conncheck.opensuse.org"; + private static final String OPENSUSE_HTTP_URL = + "http://conncheck.opensuse.org"; + + // Ubuntu + private static final String UBUNTU_HTTPS_URL = + "https://connectivity-check.ubuntu.com"; + private static final String UBUNTU_HTTP_URL = + "http://connectivity-check.ubuntu.com"; + + // Amazon Fire OS + private static final String AMAZON_HTTPS_URL = + "https://fireoscaptiveportal.com/generate_204"; + private static final String AMAZON_HTTP_URL = + "http://fireoscaptiveportal.com/generate_204"; + + // Microsoft Edge + private static final String MICROSOFT_HTTP_URL = + "http://edge-http.microsoft.com/captiveportal/generate_204"; + + // Kuketz, https://www.kuketz-blog.de/android-captive-portal-check-204-http-antwort-von-captiveportal-kuketz-de/ + private static final String KUKETZ_HTTPS_URL = + "https://captiveportal.kuketz.de"; + private static final String KUKETZ_HTTP_URL = + "http://captiveportal.kuketz.de"; + + // Cloudflare + private static final String CLOUDFLARE_HTTPS_URL = + "https://cp.cloudflare.com"; + private static final String CLOUDFLARE_HTTP_URL = + "http://cp.cloudflare.com"; + + // Huawei + private static final String HUAWEI_HTTPS_URL = + "https://connectivitycheck.platform.hicloud.com/generate_204"; + private static final String HUAWEI_HTTP_URL = + "http://connectivitycheck.platform.hicloud.com/generate_204"; + + // Xiaomi + private static final String XIAOMI_HTTPS_URL = + "https://connect.rom.miui.com/generate_204"; + private static final String XIAOMI_HTTP_URL = + "http://connect.rom.miui.com/generate_204"; + + // Keep this in sync! Commented options must be very last! + private static final int DISABLED_CAPTIVE_PORTAL_INTVAL = 0; + private static final int AMAZON_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 1; + private static final int CLOUDFLARE_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 2; + private static final int DIVESTOS_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 3; + private static final int STANDARD_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 4; + private static final int HUAWEI_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 5; + private static final int KUKETZ_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 6; + private static final int MICROSOFT_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 7; + private static final int OPENSUSE_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 8; + private static final int UBUNTU_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 9; + private static final int XIAOMI_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 10; + private static final int GRAPHENEOS_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 11; + + private static final String KEY_CONNECTIVITY_CHECK_SETTINGS = + "connectivity_check_settings"; + + private ListPreference mConnectivityPreference; + + public ConnectivityCheckPreferenceController(Context context) { + super(context, KEY_CONNECTIVITY_CHECK_SETTINGS); + } + + @Override + public int getAvailabilityStatus() { + if (isDisabledByAdmin()) { + return BasePreferenceController.DISABLED_FOR_USER; + } + return BasePreferenceController.AVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mConnectivityPreference = + screen.findPreference(KEY_CONNECTIVITY_CHECK_SETTINGS); + updatePreferenceState(); + } + + @Override + public String getPreferenceKey() { + return KEY_CONNECTIVITY_CHECK_SETTINGS; + } + + private void updatePreferenceState() { + if (Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.CAPTIVE_PORTAL_MODE, Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT) + == Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE) { + mConnectivityPreference.setValueIndex(DISABLED_CAPTIVE_PORTAL_INTVAL); + return; + } + + String pref = Settings.Global.getString( + mContext.getContentResolver(), Settings.Global.CAPTIVE_PORTAL_HTTP_URL); + if (STANDARD_HTTP_URL.equals(pref)) { + mConnectivityPreference.setValueIndex( + STANDARD_CAPTIVE_PORTAL_HTTP_URL_INTVAL); + } else if (GRAPHENEOS_CAPTIVE_PORTAL_HTTP_URL.equals(pref)) { + mConnectivityPreference.setValueIndex( + GRAPHENEOS_CAPTIVE_PORTAL_HTTP_URL_INTVAL); + } else if (DIVESTOS_HTTP_URL.equals(pref)) { + mConnectivityPreference.setValueIndex( + DIVESTOS_CAPTIVE_PORTAL_HTTP_URL_INTVAL); + } else if (OPENSUSE_HTTP_URL.equals(pref)) { + mConnectivityPreference.setValueIndex( + OPENSUSE_CAPTIVE_PORTAL_HTTP_URL_INTVAL); + } else if (UBUNTU_HTTP_URL.equals(pref)) { + mConnectivityPreference.setValueIndex( + UBUNTU_CAPTIVE_PORTAL_HTTP_URL_INTVAL); + } else if (AMAZON_HTTP_URL.equals(pref)) { + mConnectivityPreference.setValueIndex( + AMAZON_CAPTIVE_PORTAL_HTTP_URL_INTVAL); + } else if (MICROSOFT_HTTP_URL.equals(pref)) { + mConnectivityPreference.setValueIndex( + MICROSOFT_CAPTIVE_PORTAL_HTTP_URL_INTVAL); + } else if (KUKETZ_HTTP_URL.equals(pref)) { + mConnectivityPreference.setValueIndex( + KUKETZ_CAPTIVE_PORTAL_HTTP_URL_INTVAL); + } else if (CLOUDFLARE_HTTP_URL.equals(pref)) { + mConnectivityPreference.setValueIndex( + CLOUDFLARE_CAPTIVE_PORTAL_HTTP_URL_INTVAL); + } else if (HUAWEI_HTTP_URL.equals(pref)) { + mConnectivityPreference.setValueIndex( + HUAWEI_CAPTIVE_PORTAL_HTTP_URL_INTVAL); + } else if (XIAOMI_HTTP_URL.equals(pref)) { + mConnectivityPreference.setValueIndex( + XIAOMI_CAPTIVE_PORTAL_HTTP_URL_INTVAL); + } + + } + + @Override + public void onResume() { + updatePreferenceState(); + if (mConnectivityPreference != null) { + setCaptivePortalURLs( + mContext.getContentResolver(), + Integer.parseInt(mConnectivityPreference.getValue())); + } + } + + private void setCaptivePortalURLs(ContentResolver cr, int mode) { + switch (mode) { + case STANDARD_CAPTIVE_PORTAL_HTTP_URL_INTVAL: + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + STANDARD_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, + STANDARD_HTTPS_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, + STANDARD_FALLBACK_URL); + Settings.Global.putString( + cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, + STANDARD_OTHER_FALLBACK_URLS); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + break; + case GRAPHENEOS_CAPTIVE_PORTAL_HTTP_URL_INTVAL: + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + GRAPHENEOS_CAPTIVE_PORTAL_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, + GRAPHENEOS_CAPTIVE_PORTAL_HTTPS_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, + GRAPHENEOS_CAPTIVE_PORTAL_FALLBACK_URL); + Settings.Global.putString( + cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, + GRAPHENEOS_CAPTIVE_PORTAL_OTHER_FALLBACK_URL); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + break; + case DIVESTOS_CAPTIVE_PORTAL_HTTP_URL_INTVAL: + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + DIVESTOS_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, + DIVESTOS_HTTPS_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, + DIVESTOS_HTTP_URL); + Settings.Global.putString( + cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, + DIVESTOS_HTTP_URL); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + break; + case OPENSUSE_CAPTIVE_PORTAL_HTTP_URL_INTVAL: + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + OPENSUSE_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, + OPENSUSE_HTTPS_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, + OPENSUSE_HTTP_URL); + Settings.Global.putString( + cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, + OPENSUSE_HTTP_URL); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + break; + case UBUNTU_CAPTIVE_PORTAL_HTTP_URL_INTVAL: + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + UBUNTU_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, + UBUNTU_HTTPS_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, + UBUNTU_HTTP_URL); + Settings.Global.putString( + cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, + UBUNTU_HTTP_URL); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + break; + case AMAZON_CAPTIVE_PORTAL_HTTP_URL_INTVAL: + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + AMAZON_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, + AMAZON_HTTPS_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, + AMAZON_HTTP_URL); + Settings.Global.putString( + cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, + AMAZON_HTTP_URL); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + break; + case MICROSOFT_CAPTIVE_PORTAL_HTTP_URL_INTVAL: + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + MICROSOFT_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, + MICROSOFT_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, + MICROSOFT_HTTP_URL); + Settings.Global.putString( + cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, + MICROSOFT_HTTP_URL); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + break; + case KUKETZ_CAPTIVE_PORTAL_HTTP_URL_INTVAL: + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + KUKETZ_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, + KUKETZ_HTTPS_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, + KUKETZ_HTTP_URL); + Settings.Global.putString( + cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, + KUKETZ_HTTP_URL); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + break; + case CLOUDFLARE_CAPTIVE_PORTAL_HTTP_URL_INTVAL: + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + CLOUDFLARE_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, + CLOUDFLARE_HTTPS_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, + CLOUDFLARE_HTTP_URL); + Settings.Global.putString( + cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, + CLOUDFLARE_HTTP_URL); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + break; + case HUAWEI_CAPTIVE_PORTAL_HTTP_URL_INTVAL: + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + HUAWEI_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, + HUAWEI_HTTPS_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, + HUAWEI_HTTP_URL); + Settings.Global.putString( + cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, + HUAWEI_HTTP_URL); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + break; + case XIAOMI_CAPTIVE_PORTAL_HTTP_URL_INTVAL: + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + XIAOMI_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, + XIAOMI_HTTPS_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, + XIAOMI_HTTP_URL); + Settings.Global.putString( + cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, + XIAOMI_HTTP_URL); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + break; + default: + // Default URLs as placeholder + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + STANDARD_HTTP_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, + STANDARD_HTTPS_URL); + Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, + STANDARD_FALLBACK_URL); + Settings.Global.putString( + cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, + STANDARD_OTHER_FALLBACK_URLS); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE); + } + } + + @Override + public boolean onPreferenceChange(Preference preference, Object value) { + final String key = preference.getKey(); + if (KEY_CONNECTIVITY_CHECK_SETTINGS.equals(key)) { + setCaptivePortalURLs(mContext.getContentResolver(), + Integer.parseInt((String)value)); + return true; + } else { + return false; + } + } + + private EnforcedAdmin getEnforcedAdmin() { + return RestrictedLockUtilsInternal.checkIfRestrictionEnforced( + mContext, UserManager.DISALLOW_CONFIG_PRIVATE_DNS, + UserHandle.myUserId()); + } + + private boolean isDisabledByAdmin() { return getEnforcedAdmin() != null; } +} diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java index db704ae850d..c77b07821e1 100644 --- a/src/com/android/settings/network/NetworkDashboardFragment.java +++ b/src/com/android/settings/network/NetworkDashboardFragment.java @@ -103,6 +103,8 @@ public class NetworkDashboardFragment extends DashboardFragment implements new VpnPreferenceController(context); final PrivateDnsPreferenceController privateDnsPreferenceController = new PrivateDnsPreferenceController(context); + final ConnectivityCheckPreferenceController connectivityCheckPreferenceController = + new ConnectivityCheckPreferenceController(context); if (lifecycle != null) { lifecycle.addObserver(mobilePlanPreferenceController); @@ -120,6 +122,7 @@ public class NetworkDashboardFragment extends DashboardFragment implements controllers.add(mobilePlanPreferenceController); controllers.add(wifiPreferenceController); controllers.add(privateDnsPreferenceController); + controllers.add(connectivityCheckPreferenceController); return controllers; }