| /* |
| * Copyright (C) 2017 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.networkstack.tethering; |
| |
| import static android.net.ConnectivityManager.TYPE_ETHERNET; |
| import static android.net.ConnectivityManager.TYPE_MOBILE; |
| import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; |
| import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; |
| import static android.net.ConnectivityManager.TYPE_WIFI; |
| import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; |
| import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; |
| |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; |
| import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_FORCE_USB_FUNCTIONS; |
| import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_USB_NCM_FUNCTION; |
| import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_USB_RNDIS_FUNCTION; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| import static org.mockito.ArgumentMatchers.anyInt; |
| import static org.mockito.Matchers.eq; |
| import static org.mockito.Mockito.when; |
| |
| import android.content.Context; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.ModuleInfo; |
| import android.content.pm.PackageInfo; |
| import android.content.pm.PackageManager; |
| import android.content.res.Resources; |
| import android.net.util.SharedLog; |
| import android.os.Build; |
| import android.provider.DeviceConfig; |
| import android.provider.Settings; |
| import android.telephony.TelephonyManager; |
| import android.test.mock.MockContentResolver; |
| |
| import androidx.test.filters.SmallTest; |
| import androidx.test.runner.AndroidJUnit4; |
| |
| import com.android.internal.util.test.BroadcastInterceptingContext; |
| import com.android.internal.util.test.FakeSettingsProvider; |
| import com.android.net.module.util.DeviceConfigUtils; |
| import com.android.testutils.DevSdkIgnoreRule; |
| import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter; |
| import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.Mock; |
| import org.mockito.MockitoSession; |
| import org.mockito.quality.Strictness; |
| |
| import java.util.Arrays; |
| import java.util.Iterator; |
| |
| @RunWith(AndroidJUnit4.class) |
| @SmallTest |
| public class TetheringConfigurationTest { |
| private final SharedLog mLog = new SharedLog("TetheringConfigurationTest"); |
| |
| @Rule public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); |
| |
| private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; |
| private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; |
| private static final String PROVISIONING_APP_RESPONSE = "app_response"; |
| private static final String TEST_PACKAGE_NAME = "com.android.tethering.test"; |
| private static final String APEX_NAME = "com.android.tethering"; |
| private static final long TEST_PACKAGE_VERSION = 1234L; |
| @Mock private ApplicationInfo mApplicationInfo; |
| @Mock private Context mContext; |
| @Mock private TelephonyManager mTelephonyManager; |
| @Mock private Resources mResources; |
| @Mock private Resources mResourcesForSubId; |
| @Mock private PackageManager mPackageManager; |
| @Mock private ModuleInfo mMi; |
| private Context mMockContext; |
| private boolean mHasTelephonyManager; |
| private boolean mEnableLegacyDhcpServer; |
| private MockitoSession mMockingSession; |
| private MockContentResolver mContentResolver; |
| |
| private class MockTetheringConfiguration extends TetheringConfiguration { |
| MockTetheringConfiguration(Context ctx, SharedLog log, int id) { |
| super(ctx, log, id); |
| } |
| |
| @Override |
| protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) { |
| return mResourcesForSubId; |
| } |
| } |
| |
| private class MockContext extends BroadcastInterceptingContext { |
| MockContext(Context base) { |
| super(base); |
| } |
| |
| @Override |
| public ApplicationInfo getApplicationInfo() { |
| return mApplicationInfo; |
| } |
| |
| @Override |
| public Resources getResources() { |
| return mResources; |
| } |
| |
| @Override |
| public Object getSystemService(String name) { |
| if (Context.TELEPHONY_SERVICE.equals(name)) { |
| return mHasTelephonyManager ? mTelephonyManager : null; |
| } |
| return super.getSystemService(name); |
| } |
| |
| @Override |
| public PackageManager getPackageManager() { |
| return mPackageManager; |
| } |
| |
| @Override |
| public String getPackageName() { |
| return TEST_PACKAGE_NAME; |
| } |
| } |
| |
| @Before |
| public void setUp() throws Exception { |
| // TODO: use a dependencies class instead of mock statics. |
| mMockingSession = mockitoSession() |
| .initMocks(this) |
| .mockStatic(DeviceConfig.class) |
| .strictness(Strictness.WARN) |
| .startMocking(); |
| DeviceConfigUtils.resetPackageVersionCacheForTest(); |
| doReturn(null).when( |
| () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), |
| eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); |
| setTetherForceUpstreamAutomaticFlagVersion(null); |
| |
| final PackageInfo pi = new PackageInfo(); |
| pi.setLongVersionCode(TEST_PACKAGE_VERSION); |
| doReturn(pi).when(mPackageManager).getPackageInfo(eq(TEST_PACKAGE_NAME), anyInt()); |
| doReturn(mMi).when(mPackageManager).getModuleInfo(eq(APEX_NAME), anyInt()); |
| doReturn(TEST_PACKAGE_NAME).when(mMi).getPackageName(); |
| |
| when(mResources.getStringArray(R.array.config_tether_dhcp_range)).thenReturn( |
| new String[0]); |
| when(mResources.getInteger(R.integer.config_tether_offload_poll_interval)).thenReturn( |
| TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); |
| when(mResources.getStringArray(R.array.config_tether_usb_regexs)) |
| .thenReturn(new String[]{ "test_usb\\d" }); |
| when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) |
| .thenReturn(new String[]{ "test_wlan\\d" }); |
| when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)).thenReturn( |
| new String[0]); |
| when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]); |
| when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app)) |
| .thenReturn(new String[0]); |
| when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( |
| false); |
| when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip)) |
| .thenReturn(false); |
| initializeBpfOffloadConfiguration(true, null /* unset */); |
| |
| mHasTelephonyManager = true; |
| mMockContext = new MockContext(mContext); |
| mEnableLegacyDhcpServer = false; |
| |
| mContentResolver = new MockContentResolver(mMockContext); |
| mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); |
| when(mContext.getContentResolver()).thenReturn(mContentResolver); |
| // Call {@link #clearSettingsProvider()} before and after using FakeSettingsProvider. |
| FakeSettingsProvider.clearSettingsProvider(); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| mMockingSession.finishMocking(); |
| DeviceConfigUtils.resetPackageVersionCacheForTest(); |
| // Call {@link #clearSettingsProvider()} before and after using FakeSettingsProvider. |
| FakeSettingsProvider.clearSettingsProvider(); |
| } |
| |
| private TetheringConfiguration getTetheringConfiguration(int... legacyTetherUpstreamTypes) { |
| when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn( |
| legacyTetherUpstreamTypes); |
| return new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| } |
| |
| @Test |
| public void testNoTelephonyManagerMeansNoDun() { |
| mHasTelephonyManager = false; |
| final TetheringConfiguration cfg = getTetheringConfiguration( |
| new int[]{TYPE_MOBILE_DUN, TYPE_WIFI}); |
| assertFalse(cfg.isDunRequired); |
| assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); |
| // Just to prove we haven't clobbered Wi-Fi: |
| assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); |
| } |
| |
| @Test |
| public void testDunFromTelephonyManagerMeansDun() { |
| when(mTelephonyManager.isTetheringApnRequired()).thenReturn(true); |
| |
| final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI); |
| final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( |
| TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI); |
| final TetheringConfiguration cfgWifiDun = getTetheringConfiguration( |
| TYPE_WIFI, TYPE_MOBILE_DUN); |
| final TetheringConfiguration cfgMobileWifiHipriDun = getTetheringConfiguration( |
| TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI, TYPE_MOBILE_DUN); |
| |
| for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, |
| cfgWifiDun, cfgMobileWifiHipriDun)) { |
| String msg = "config=" + cfg.toString(); |
| assertTrue(msg, cfg.isDunRequired); |
| assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); |
| assertFalse(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); |
| assertFalse(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); |
| // Just to prove we haven't clobbered Wi-Fi: |
| assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); |
| } |
| } |
| |
| @Test |
| public void testDunNotRequiredFromTelephonyManagerMeansNoDun() { |
| when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); |
| |
| final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI); |
| final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( |
| TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI); |
| final TetheringConfiguration cfgWifiDun = getTetheringConfiguration( |
| TYPE_WIFI, TYPE_MOBILE_DUN); |
| final TetheringConfiguration cfgWifiMobile = getTetheringConfiguration( |
| TYPE_WIFI, TYPE_MOBILE); |
| final TetheringConfiguration cfgWifiHipri = getTetheringConfiguration( |
| TYPE_WIFI, TYPE_MOBILE_HIPRI); |
| final TetheringConfiguration cfgMobileWifiHipriDun = getTetheringConfiguration( |
| TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI, TYPE_MOBILE_DUN); |
| |
| String msg; |
| // TYPE_MOBILE_DUN should be present in none of the combinations. |
| // TYPE_WIFI should not be affected. |
| for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, cfgWifiDun, |
| cfgWifiMobile, cfgWifiHipri, cfgMobileWifiHipriDun)) { |
| msg = "config=" + cfg.toString(); |
| assertFalse(msg, cfg.isDunRequired); |
| assertFalse(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); |
| assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); |
| } |
| |
| for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, cfgWifiDun, |
| cfgMobileWifiHipriDun)) { |
| msg = "config=" + cfg.toString(); |
| assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); |
| assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); |
| } |
| msg = "config=" + cfgWifiMobile.toString(); |
| assertTrue(msg, cfgWifiMobile.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); |
| assertFalse(msg, cfgWifiMobile.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); |
| msg = "config=" + cfgWifiHipri.toString(); |
| assertFalse(msg, cfgWifiHipri.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); |
| assertTrue(msg, cfgWifiHipri.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); |
| |
| } |
| |
| @Test |
| public void testNoDefinedUpstreamTypesAddsEthernet() { |
| when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[]{}); |
| when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); |
| |
| final TetheringConfiguration cfg = new TetheringConfiguration( |
| mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); |
| assertTrue(upstreamIterator.hasNext()); |
| assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); |
| // The following is because the code always adds some kind of mobile |
| // upstream, be it DUN or, in this case where DUN is NOT required, |
| // make sure there is at least one of MOBILE or HIPRI. With the empty |
| // list of the configuration in this test, it will always add both |
| // MOBILE and HIPRI, in that order. |
| assertTrue(upstreamIterator.hasNext()); |
| assertEquals(TYPE_MOBILE, upstreamIterator.next().intValue()); |
| assertTrue(upstreamIterator.hasNext()); |
| assertEquals(TYPE_MOBILE_HIPRI, upstreamIterator.next().intValue()); |
| assertFalse(upstreamIterator.hasNext()); |
| } |
| |
| @Test |
| public void testDefinedUpstreamTypesSansEthernetAddsEthernet() { |
| when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn( |
| new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI}); |
| when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); |
| |
| final TetheringConfiguration cfg = new TetheringConfiguration( |
| mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); |
| assertTrue(upstreamIterator.hasNext()); |
| assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); |
| assertTrue(upstreamIterator.hasNext()); |
| assertEquals(TYPE_WIFI, upstreamIterator.next().intValue()); |
| assertTrue(upstreamIterator.hasNext()); |
| assertEquals(TYPE_MOBILE_HIPRI, upstreamIterator.next().intValue()); |
| assertFalse(upstreamIterator.hasNext()); |
| } |
| |
| @Test |
| public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() { |
| when(mResources.getIntArray(R.array.config_tether_upstream_types)) |
| .thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI}); |
| when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); |
| |
| final TetheringConfiguration cfg = new TetheringConfiguration( |
| mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); |
| assertTrue(upstreamIterator.hasNext()); |
| assertEquals(TYPE_WIFI, upstreamIterator.next().intValue()); |
| assertTrue(upstreamIterator.hasNext()); |
| assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); |
| assertTrue(upstreamIterator.hasNext()); |
| assertEquals(TYPE_MOBILE_HIPRI, upstreamIterator.next().intValue()); |
| assertFalse(upstreamIterator.hasNext()); |
| } |
| |
| private void initializeBpfOffloadConfiguration( |
| final boolean fromRes, final String fromDevConfig) { |
| when(mResources.getBoolean(R.bool.config_tether_enable_bpf_offload)).thenReturn(fromRes); |
| doReturn(fromDevConfig).when( |
| () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), |
| eq(TetheringConfiguration.OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD))); |
| } |
| |
| @Test |
| public void testBpfOffloadEnabledByResource() { |
| initializeBpfOffloadConfiguration(true, null /* unset */); |
| final TetheringConfiguration enableByRes = |
| new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertTrue(enableByRes.isBpfOffloadEnabled()); |
| } |
| |
| @Test |
| public void testBpfOffloadEnabledByDeviceConfigOverride() { |
| for (boolean res : new boolean[]{true, false}) { |
| initializeBpfOffloadConfiguration(res, "true"); |
| final TetheringConfiguration enableByDevConOverride = |
| new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertTrue(enableByDevConOverride.isBpfOffloadEnabled()); |
| } |
| } |
| |
| @Test |
| public void testBpfOffloadDisabledByResource() { |
| initializeBpfOffloadConfiguration(false, null /* unset */); |
| final TetheringConfiguration disableByRes = |
| new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertFalse(disableByRes.isBpfOffloadEnabled()); |
| } |
| |
| @Test |
| public void testBpfOffloadDisabledByDeviceConfigOverride() { |
| for (boolean res : new boolean[]{true, false}) { |
| initializeBpfOffloadConfiguration(res, "false"); |
| final TetheringConfiguration disableByDevConOverride = |
| new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertFalse(disableByDevConOverride.isBpfOffloadEnabled()); |
| } |
| } |
| |
| @Test |
| public void testNewDhcpServerDisabled() { |
| when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( |
| true); |
| doReturn("false").when( |
| () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), |
| eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); |
| |
| final TetheringConfiguration enableByRes = |
| new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertTrue(enableByRes.enableLegacyDhcpServer); |
| |
| when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( |
| false); |
| doReturn("true").when( |
| () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), |
| eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); |
| |
| final TetheringConfiguration enableByDevConfig = |
| new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertTrue(enableByDevConfig.enableLegacyDhcpServer); |
| } |
| |
| @Test |
| public void testNewDhcpServerEnabled() { |
| when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( |
| false); |
| doReturn("false").when( |
| () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), |
| eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); |
| |
| final TetheringConfiguration cfg = |
| new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| |
| assertFalse(cfg.enableLegacyDhcpServer); |
| } |
| |
| @Test |
| public void testOffloadIntervalByResource() { |
| final TetheringConfiguration intervalByDefault = |
| new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertEquals(TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS, |
| intervalByDefault.getOffloadPollInterval()); |
| |
| final int[] testOverrides = {0, 3000, -1}; |
| for (final int override : testOverrides) { |
| when(mResources.getInteger(R.integer.config_tether_offload_poll_interval)).thenReturn( |
| override); |
| final TetheringConfiguration overrideByRes = |
| new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertEquals(override, overrideByRes.getOffloadPollInterval()); |
| } |
| } |
| |
| @Test |
| public void testGetResourcesBySubId() { |
| setUpResourceForSubId(); |
| final TetheringConfiguration cfg = new TetheringConfiguration( |
| mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertTrue(cfg.provisioningApp.length == 0); |
| final int anyValidSubId = 1; |
| final MockTetheringConfiguration mockCfg = |
| new MockTetheringConfiguration(mMockContext, mLog, anyValidSubId); |
| assertEquals(mockCfg.provisioningApp[0], PROVISIONING_APP_NAME[0]); |
| assertEquals(mockCfg.provisioningApp[1], PROVISIONING_APP_NAME[1]); |
| assertEquals(mockCfg.provisioningAppNoUi, PROVISIONING_NO_UI_APP_NAME); |
| assertEquals(mockCfg.provisioningResponse, PROVISIONING_APP_RESPONSE); |
| } |
| |
| private void setUpResourceForSubId() { |
| when(mResourcesForSubId.getStringArray( |
| R.array.config_tether_dhcp_range)).thenReturn(new String[0]); |
| when(mResourcesForSubId.getStringArray( |
| R.array.config_tether_usb_regexs)).thenReturn(new String[0]); |
| when(mResourcesForSubId.getStringArray( |
| R.array.config_tether_wifi_regexs)).thenReturn(new String[]{ "test_wlan\\d" }); |
| when(mResourcesForSubId.getStringArray( |
| R.array.config_tether_bluetooth_regexs)).thenReturn(new String[0]); |
| when(mResourcesForSubId.getIntArray(R.array.config_tether_upstream_types)).thenReturn( |
| new int[0]); |
| when(mResourcesForSubId.getStringArray( |
| R.array.config_mobile_hotspot_provision_app)).thenReturn(PROVISIONING_APP_NAME); |
| when(mResourcesForSubId.getString(R.string.config_mobile_hotspot_provision_app_no_ui)) |
| .thenReturn(PROVISIONING_NO_UI_APP_NAME); |
| when(mResourcesForSubId.getString( |
| R.string.config_mobile_hotspot_provision_response)).thenReturn( |
| PROVISIONING_APP_RESPONSE); |
| } |
| |
| @Test |
| public void testEnableLegacyWifiP2PAddress() throws Exception { |
| final TetheringConfiguration defaultCfg = new TetheringConfiguration( |
| mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertFalse(defaultCfg.shouldEnableWifiP2pDedicatedIp()); |
| |
| when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip)) |
| .thenReturn(true); |
| final TetheringConfiguration testCfg = new TetheringConfiguration( |
| mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertTrue(testCfg.shouldEnableWifiP2pDedicatedIp()); |
| } |
| |
| @Test |
| public void testChooseUpstreamAutomatically() throws Exception { |
| when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)) |
| .thenReturn(true); |
| assertChooseUpstreamAutomaticallyIs(true); |
| |
| when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)) |
| .thenReturn(false); |
| assertChooseUpstreamAutomaticallyIs(false); |
| } |
| |
| // The flag override only works on R- |
| @Test @IgnoreAfter(Build.VERSION_CODES.R) |
| public void testChooseUpstreamAutomatically_FlagOverride() throws Exception { |
| when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)) |
| .thenReturn(false); |
| setTetherForceUpstreamAutomaticFlagVersion(TEST_PACKAGE_VERSION - 1); |
| assertTrue(DeviceConfigUtils.isFeatureEnabled(mMockContext, NAMESPACE_CONNECTIVITY, |
| TetheringConfiguration.TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION, APEX_NAME, false)); |
| |
| assertChooseUpstreamAutomaticallyIs(true); |
| |
| setTetherForceUpstreamAutomaticFlagVersion(0L); |
| assertChooseUpstreamAutomaticallyIs(false); |
| |
| setTetherForceUpstreamAutomaticFlagVersion(Long.MAX_VALUE); |
| assertChooseUpstreamAutomaticallyIs(false); |
| } |
| |
| @Test @IgnoreUpTo(Build.VERSION_CODES.R) |
| public void testChooseUpstreamAutomatically_FlagOverrideAfterR() throws Exception { |
| when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)) |
| .thenReturn(false); |
| setTetherForceUpstreamAutomaticFlagVersion(TEST_PACKAGE_VERSION - 1); |
| assertChooseUpstreamAutomaticallyIs(false); |
| } |
| |
| private void setTetherForceUpstreamAutomaticFlagVersion(Long version) { |
| doReturn(version == null ? null : Long.toString(version)).when( |
| () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), |
| eq(TetheringConfiguration.TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION))); |
| } |
| |
| private void assertChooseUpstreamAutomaticallyIs(boolean value) { |
| assertEquals(value, new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID) |
| .chooseUpstreamAutomatically); |
| } |
| |
| @Test |
| public void testUsbTetheringFunctions() throws Exception { |
| // Test default value. If both resource and settings is not configured, usingNcm is false. |
| assertIsUsingNcm(false /* usingNcm */); |
| |
| when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn( |
| TETHER_USB_NCM_FUNCTION); |
| assertIsUsingNcm(true /* usingNcm */); |
| |
| when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn( |
| TETHER_USB_RNDIS_FUNCTION); |
| assertIsUsingNcm(false /* usingNcm */); |
| |
| setTetherForceUsbFunctions(TETHER_USB_RNDIS_FUNCTION); |
| assertIsUsingNcm(false /* usingNcm */); |
| |
| setTetherForceUsbFunctions(TETHER_USB_NCM_FUNCTION); |
| assertIsUsingNcm(true /* usingNcm */); |
| |
| // Test throws NumberFormatException. |
| setTetherForceUsbFunctions("WrongNumberFormat"); |
| assertIsUsingNcm(false /* usingNcm */); |
| } |
| |
| private void assertIsUsingNcm(boolean expected) { |
| final TetheringConfiguration cfg = |
| new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertEquals(expected, cfg.isUsingNcm()); |
| } |
| |
| private void setTetherForceUsbFunctions(final String value) { |
| Settings.Global.putString(mContentResolver, TETHER_FORCE_USB_FUNCTIONS, value); |
| } |
| |
| private void setTetherForceUsbFunctions(final int value) { |
| setTetherForceUsbFunctions(Integer.toString(value)); |
| } |
| |
| @Test |
| public void testNcmRegexs() throws Exception { |
| final String[] rndisRegexs = {"test_rndis\\d"}; |
| final String[] ncmRegexs = {"test_ncm\\d"}; |
| final String[] rndisNcmRegexs = {"test_rndis\\d", "test_ncm\\d"}; |
| |
| // cfg.isUsingNcm = false. |
| when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn( |
| TETHER_USB_RNDIS_FUNCTION); |
| setUsbAndNcmRegexs(rndisRegexs, ncmRegexs); |
| assertUsbAndNcmRegexs(rndisRegexs, ncmRegexs); |
| |
| setUsbAndNcmRegexs(rndisNcmRegexs, new String[0]); |
| assertUsbAndNcmRegexs(rndisNcmRegexs, new String[0]); |
| |
| // cfg.isUsingNcm = true. |
| when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn( |
| TETHER_USB_NCM_FUNCTION); |
| setUsbAndNcmRegexs(rndisRegexs, ncmRegexs); |
| assertUsbAndNcmRegexs(ncmRegexs, new String[0]); |
| |
| setUsbAndNcmRegexs(rndisNcmRegexs, new String[0]); |
| assertUsbAndNcmRegexs(rndisNcmRegexs, new String[0]); |
| |
| // Check USB regex is not overwritten by the NCM regex after force to use rndis from |
| // Settings. |
| setUsbAndNcmRegexs(rndisRegexs, ncmRegexs); |
| setTetherForceUsbFunctions(TETHER_USB_RNDIS_FUNCTION); |
| assertUsbAndNcmRegexs(rndisRegexs, ncmRegexs); |
| } |
| |
| private void setUsbAndNcmRegexs(final String[] usbRegexs, final String[] ncmRegexs) { |
| when(mResources.getStringArray(R.array.config_tether_usb_regexs)).thenReturn(usbRegexs); |
| when(mResources.getStringArray(R.array.config_tether_ncm_regexs)).thenReturn(ncmRegexs); |
| } |
| |
| private void assertUsbAndNcmRegexs(final String[] usbRegexs, final String[] ncmRegexs) { |
| final TetheringConfiguration cfg = |
| new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); |
| assertArrayEquals(usbRegexs, cfg.tetherableUsbRegexs); |
| assertArrayEquals(ncmRegexs, cfg.tetherableNcmRegexs); |
| } |
| |
| } |