diff --git a/res/xml/tether_prefs.xml b/res/xml/tether_prefs.xml
index 2a841d71608..70a57d7c98a 100644
--- a/res/xml/tether_prefs.xml
+++ b/res/xml/tether_prefs.xml
@@ -17,6 +17,7 @@
+ android:summary="@string/usb_tethering_subtext"
+ settings:keywords="@string/keywords_hotspot_tethering" />
+ android:summary="@string/bluetooth_tethering_subtext"
+ settings:keywords="@string/keywords_hotspot_tethering" />
@@ -43,4 +44,4 @@
android:dialogTitle="@string/wifi_hotspot_ap_band_title"
android:negativeButtonText="@string/cancel"
android:positiveButtonText="@string/apply"/>
-
\ No newline at end of file
+
diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java
index 8cb8efc27df..848e1765699 100644
--- a/src/com/android/settings/TetherSettings.java
+++ b/src/com/android/settings/TetherSettings.java
@@ -34,27 +34,41 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.UserManager;
-import androidx.preference.SwitchPreference;
+import android.provider.SearchIndexableResource;
+import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.datausage.DataSaverBackend;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
import com.android.settings.wifi.tether.WifiTetherPreferenceController;
import com.android.settingslib.TetherUtil;
+import com.android.settingslib.search.SearchIndexable;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/*
* Displays preferences for Tethering.
*/
+@SearchIndexable
public class TetherSettings extends RestrictedSettingsFragment
implements DataSaverBackend.Listener {
- private static final String USB_TETHER_SETTINGS = "usb_tether_settings";
- private static final String ENABLE_BLUETOOTH_TETHERING = "enable_bluetooth_tethering";
- private static final String DATA_SAVER_FOOTER = "disabled_on_data_saver";
+ @VisibleForTesting
+ static final String KEY_TETHER_PREFS_SCREEN = "tether_prefs_screen";
+ @VisibleForTesting
+ static final String KEY_WIFI_TETHER = "wifi_tether";
+ @VisibleForTesting
+ static final String KEY_USB_TETHER_SETTINGS = "usb_tether_settings";
+ @VisibleForTesting
+ static final String KEY_ENABLE_BLUETOOTH_TETHERING = "enable_bluetooth_tethering";
+ private static final String KEY_DATA_SAVER_FOOTER = "disabled_on_data_saver";
private static final String TAG = "TetheringSettings";
@@ -110,7 +124,7 @@ public class TetherSettings extends RestrictedSettingsFragment
mDataSaverBackend = new DataSaverBackend(getContext());
mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled();
- mDataSaverFooter = findPreference(DATA_SAVER_FOOTER);
+ mDataSaverFooter = findPreference(KEY_DATA_SAVER_FOOTER);
setIfOnlyAvailableForAdmins(true);
if (isUiRestricted()) {
@@ -126,8 +140,8 @@ public class TetherSettings extends RestrictedSettingsFragment
BluetoothProfile.PAN);
}
- mUsbTether = (SwitchPreference) findPreference(USB_TETHER_SETTINGS);
- mBluetoothTether = (SwitchPreference) findPreference(ENABLE_BLUETOOTH_TETHERING);
+ mUsbTether = (SwitchPreference) findPreference(KEY_USB_TETHER_SETTINGS);
+ mBluetoothTether = (SwitchPreference) findPreference(KEY_ENABLE_BLUETOOTH_TETHERING);
mDataSaverBackend.addListener(this);
@@ -433,6 +447,42 @@ public class TetherSettings extends RestrictedSettingsFragment
}
};
+ public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List getXmlResourcesToIndex(
+ Context context, boolean enabled) {
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.tether_prefs;
+ return Arrays.asList(sir);
+ }
+
+ @Override
+ public List getNonIndexableKeys(Context context) {
+ final List keys = super.getNonIndexableKeys(context);
+ final ConnectivityManager cm =
+ context.getSystemService(ConnectivityManager.class);
+
+ if (!TetherUtil.isTetherAvailable(context)) {
+ keys.add(KEY_TETHER_PREFS_SCREEN);
+ keys.add(KEY_WIFI_TETHER);
+ }
+
+ final boolean usbAvailable =
+ cm.getTetherableUsbRegexs().length != 0;
+ if (!usbAvailable || Utils.isMonkeyRunning()) {
+ keys.add(KEY_USB_TETHER_SETTINGS);
+ }
+
+ final boolean bluetoothAvailable =
+ cm.getTetherableBluetoothRegexs().length != 0;
+ if (!bluetoothAvailable) {
+ keys.add(KEY_ENABLE_BLUETOOTH_TETHERING);
+ }
+ return keys;
+ }
+ };
+
private static final class OnStartTetheringCallback extends
ConnectivityManager.OnStartTetheringCallback {
final WeakReference mTetherSettings;
diff --git a/src/com/android/settings/network/TetherPreferenceController.java b/src/com/android/settings/network/TetherPreferenceController.java
index 636fe0cee07..3ab83cda0b5 100644
--- a/src/com/android/settings/network/TetherPreferenceController.java
+++ b/src/com/android/settings/network/TetherPreferenceController.java
@@ -17,7 +17,6 @@ package com.android.settings.network;
import static android.os.UserManager.DISALLOW_CONFIG_TETHERING;
import static com.android.settingslib.RestrictedLockUtils.checkIfRestrictionEnforced;
-import static com.android.settingslib.RestrictedLockUtils.hasBaseUserRestriction;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothPan;
@@ -40,6 +39,7 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.TetherSettings;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.TetherUtil;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -112,11 +112,7 @@ public class TetherPreferenceController extends AbstractPreferenceController imp
@Override
public boolean isAvailable() {
- final boolean isBlocked =
- (!mConnectivityManager.isTetheringSupported() && !mAdminDisallowedTetherConfig)
- || hasBaseUserRestriction(mContext, DISALLOW_CONFIG_TETHERING,
- UserHandle.myUserId());
- return !isBlocked;
+ return TetherUtil.isTetherAvailable(mContext);
}
@Override
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index 7c50f0c2cdb..5e202d63471 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -27,28 +27,42 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.UserManager;
-import androidx.annotation.VisibleForTesting;
+import android.provider.SearchIndexableResource;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.SwitchBarController;
+import com.android.settingslib.TetherUtil;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.UUID;
+@SearchIndexable
public class WifiTetherSettings extends RestrictedDashboardFragment
implements WifiTetherBasePreferenceController.OnTetherConfigUpdateListener {
private static final String TAG = "WifiTetherSettings";
private static final IntentFilter TETHER_STATE_CHANGE_FILTER;
- private static final String KEY_WIFI_TETHER_AUTO_OFF = "wifi_tether_auto_turn_off";
+ private static final String KEY_WIFI_TETHER_SCREEN = "wifi_tether_settings_screen";
+ @VisibleForTesting
+ static final String KEY_WIFI_TETHER_NETWORK_NAME = "wifi_tether_network_name";
+ @VisibleForTesting
+ static final String KEY_WIFI_TETHER_NETWORK_PASSWORD = "wifi_tether_network_password";
+ @VisibleForTesting
+ static final String KEY_WIFI_TETHER_AUTO_OFF = "wifi_tether_auto_turn_off";
+ @VisibleForTesting
+ static final String KEY_WIFI_TETHER_NETWORK_AP_BAND = "wifi_tether_network_ap_band";
private WifiTetherSwitchBarController mSwitchBarController;
private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
@@ -182,6 +196,33 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
.updateDisplay();
}
+ public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List getXmlResourcesToIndex(
+ Context context, boolean enabled) {
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.wifi_tether_settings;
+ return Arrays.asList(sir);
+ }
+
+ @Override
+ public List getNonIndexableKeys(Context context) {
+ final List keys = super.getNonIndexableKeys(context);
+
+ if (!TetherUtil.isTetherAvailable(context)) {
+ keys.add(KEY_WIFI_TETHER_NETWORK_NAME);
+ keys.add(KEY_WIFI_TETHER_NETWORK_PASSWORD);
+ keys.add(KEY_WIFI_TETHER_AUTO_OFF);
+ keys.add(KEY_WIFI_TETHER_NETWORK_AP_BAND);
+ }
+
+ // Remove duplicate
+ keys.add(KEY_WIFI_TETHER_SCREEN);
+ return keys;
+ }
+ };
+
@VisibleForTesting
class TetherChangeReceiver extends BroadcastReceiver {
@Override
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index 8bd4f823840..31e3a54ee26 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -21,7 +21,6 @@ com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionMi
com.android.settings.enterprise.ApplicationListFragment$EnterpriseInstalledPackages
com.android.settings.enterprise.EnterpriseSetDefaultAppsListFragment
com.android.settings.inputmethod.KeyboardLayoutPickerFragment
-com.android.settings.wifi.tether.WifiTetherSettings
com.android.settings.wifi.SavedAccessPointsWifiSettings
com.android.settings.notification.ZenModeEventRuleSettings
com.android.settings.notification.ZenModeScheduleRuleSettings
diff --git a/tests/robotests/src/com/android/settings/TetherSettingsTest.java b/tests/robotests/src/com/android/settings/TetherSettingsTest.java
new file mode 100644
index 00000000000..1ccd958cfb3
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/TetherSettingsTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.net.ConnectivityManager;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class TetherSettingsTest {
+
+ private Context mContext;
+
+ @Mock
+ private ConnectivityManager mConnectivityManager;
+ @Mock
+ private UserManager mUserManager;
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+
+ MockitoAnnotations.initMocks(this);
+ doReturn(mConnectivityManager)
+ .when(mContext).getSystemService(Context.CONNECTIVITY_SERVICE);
+ doReturn(mUserManager)
+ .when(mContext).getSystemService(Context.USER_SERVICE);
+
+ setupIsTetherAvailable(true);
+
+ when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[]{});
+ when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[]{});
+ }
+
+ @Test
+ public void testTetherNonIndexableKeys_tetherAvailable_keysNotReturned() {
+ // To let TetherUtil.isTetherAvailable return true, select one of the combinations
+ setupIsTetherAvailable(true);
+
+ final List niks =
+ TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).doesNotContain(TetherSettings.KEY_TETHER_PREFS_SCREEN);
+ assertThat(niks).doesNotContain(TetherSettings.KEY_WIFI_TETHER);
+ }
+
+ @Test
+ public void testTetherNonIndexableKeys_tetherNotAvailable_keysReturned() {
+ // To let TetherUtil.isTetherAvailable return false, select one of the combinations
+ setupIsTetherAvailable(false);
+
+ final List niks =
+ TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).contains(TetherSettings.KEY_TETHER_PREFS_SCREEN);
+ assertThat(niks).contains(TetherSettings.KEY_WIFI_TETHER);
+ }
+
+ @Test
+ public void testTetherNonIndexableKeys_usbNotAvailable_usbKeyReturned() {
+ when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[]{});
+
+ final List niks =
+ TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).contains(TetherSettings.KEY_USB_TETHER_SETTINGS);
+ }
+
+ @Test
+ public void testTetherNonIndexableKeys_usbAvailable_usbKeyNotReturned() {
+ // We can ignore the condition of Utils.isMonkeyRunning()
+ // In normal case, monkey and robotest should not execute at the same time
+ when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[]{"dummyRegex"});
+
+ final List niks =
+ TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).doesNotContain(TetherSettings.KEY_USB_TETHER_SETTINGS);
+ }
+
+ @Test
+ public void testTetherNonIndexableKeys_bluetoothNotAvailable_bluetoothKeyReturned() {
+ when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[]{});
+
+ final List niks =
+ TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).contains(TetherSettings.KEY_ENABLE_BLUETOOTH_TETHERING);
+ }
+
+ @Test
+ public void testTetherNonIndexableKeys_bluetoothAvailable_bluetoothKeyNotReturned() {
+ when(mConnectivityManager.getTetherableBluetoothRegexs())
+ .thenReturn(new String[]{"dummyRegex"});
+
+ final List niks =
+ TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).doesNotContain(TetherSettings.KEY_ENABLE_BLUETOOTH_TETHERING);
+ }
+
+ private void setupIsTetherAvailable(boolean returnValue) {
+ when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
+
+ // For RestrictedLockUtils.checkIfRestrictionEnforced
+ final int userId = UserHandle.myUserId();
+ List enforcingUsers = new ArrayList<>();
+ when(mUserManager.getUserRestrictionSources(
+ UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(userId)))
+ .thenReturn(enforcingUsers);
+
+ // For RestrictedLockUtils.hasBaseUserRestriction
+ when(mUserManager.hasBaseUserRestriction(
+ UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(userId)))
+ .thenReturn(!returnValue);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
new file mode 100644
index 00000000000..58bb1989d98
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 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.wifi.tether;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.net.ConnectivityManager;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class WifiTetherSettingsTest {
+
+ private Context mContext;
+
+ @Mock
+ private ConnectivityManager mConnectivityManager;
+ @Mock
+ private UserManager mUserManager;
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+
+ MockitoAnnotations.initMocks(this);
+ doReturn(mConnectivityManager)
+ .when(mContext).getSystemService(Context.CONNECTIVITY_SERVICE);
+ doReturn(mUserManager)
+ .when(mContext).getSystemService(Context.USER_SERVICE);
+ }
+
+ @Test
+ public void testWifiTetherNonIndexableKeys_tetherAvailable_keysNotReturned() {
+ // To let TetherUtil.isTetherAvailable return true, select one of the combinations
+ setupIsTetherAvailable(true);
+
+ final List niks =
+ WifiTetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
+ assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
+ assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
+ assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_AP_BAND);
+ }
+
+ @Test
+ public void testWifiTetherNonIndexableKeys_tetherNotAvailable_keysReturned() {
+ // To let TetherUtil.isTetherAvailable return false, select one of the combinations
+ setupIsTetherAvailable(false);
+
+ final List niks =
+ WifiTetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
+ assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
+ assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
+ assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_AP_BAND);
+ }
+
+ private void setupIsTetherAvailable(boolean returnValue) {
+ when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
+
+ // For RestrictedLockUtils.checkIfRestrictionEnforced
+ final int userId = UserHandle.myUserId();
+ List enforcingUsers = new ArrayList<>();
+ when(mUserManager.getUserRestrictionSources(
+ UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(userId)))
+ .thenReturn(enforcingUsers);
+
+ // For RestrictedLockUtils.hasBaseUserRestriction
+ when(mUserManager.hasBaseUserRestriction(
+ UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(userId)))
+ .thenReturn(!returnValue);
+ }
+}