/* * Copyright (C) 2021 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 android.net import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_IGNORE import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT import android.net.ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS import android.net.ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_MOBILE import android.net.ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_WIFI import android.net.ConnectivitySettingsManager.DNS_RESOLVER_MAX_SAMPLES import android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES import android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS import android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT import android.net.ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON import android.net.ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT import android.net.ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS import android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE import android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF import android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC import android.net.ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED import android.net.ConnectivitySettingsManager.getCaptivePortalMode import android.net.ConnectivitySettingsManager.getConnectivityKeepPendingIntentDuration import android.net.ConnectivitySettingsManager.getDnsResolverSampleRanges import android.net.ConnectivitySettingsManager.getDnsResolverSampleValidityDuration import android.net.ConnectivitySettingsManager.getDnsResolverSuccessThresholdPercent import android.net.ConnectivitySettingsManager.getIngressRateLimitInBytesPerSecond import android.net.ConnectivitySettingsManager.getMobileDataActivityTimeout import android.net.ConnectivitySettingsManager.getMobileDataAlwaysOn import android.net.ConnectivitySettingsManager.getNetworkSwitchNotificationMaximumDailyCount import android.net.ConnectivitySettingsManager.getNetworkSwitchNotificationRateDuration import android.net.ConnectivitySettingsManager.getPrivateDnsDefaultMode import android.net.ConnectivitySettingsManager.getWifiAlwaysRequested import android.net.ConnectivitySettingsManager.getWifiDataActivityTimeout import android.net.ConnectivitySettingsManager.setCaptivePortalMode import android.net.ConnectivitySettingsManager.setConnectivityKeepPendingIntentDuration import android.net.ConnectivitySettingsManager.setDnsResolverSampleRanges import android.net.ConnectivitySettingsManager.setDnsResolverSampleValidityDuration import android.net.ConnectivitySettingsManager.setDnsResolverSuccessThresholdPercent import android.net.ConnectivitySettingsManager.setIngressRateLimitInBytesPerSecond import android.net.ConnectivitySettingsManager.setMobileDataActivityTimeout import android.net.ConnectivitySettingsManager.setMobileDataAlwaysOn import android.net.ConnectivitySettingsManager.setNetworkSwitchNotificationMaximumDailyCount import android.net.ConnectivitySettingsManager.setNetworkSwitchNotificationRateDuration import android.net.ConnectivitySettingsManager.setPrivateDnsDefaultMode import android.net.ConnectivitySettingsManager.setWifiAlwaysRequested import android.net.ConnectivitySettingsManager.setWifiDataActivityTimeout import android.os.Build import android.platform.test.annotations.AppModeFull import android.provider.Settings import android.util.Range import androidx.test.InstrumentationRegistry import androidx.test.filters.SmallTest import com.android.net.module.util.ConnectivitySettingsUtils.getPrivateDnsModeAsString import com.android.testutils.ConnectivityModuleTest import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.DevSdkIgnoreRunner import junit.framework.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith import java.time.Duration import java.util.Objects import kotlin.test.assertFailsWith /** * Tests for [ConnectivitySettingsManager]. * * Build, install and run with: * atest android.net.ConnectivitySettingsManagerTest */ @RunWith(DevSdkIgnoreRunner::class) @IgnoreUpTo(Build.VERSION_CODES.R) @SmallTest @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") class ConnectivitySettingsManagerTest { private val instrumentation = InstrumentationRegistry.getInstrumentation() private val context = instrumentation.context private val resolver = context.contentResolver private val defaultDuration = Duration.ofSeconds(0L) private val testTime1 = 5L private val testTime2 = 10L private val settingsTypeGlobal = "global" private val settingsTypeSecure = "secure" /*** Reset setting value or delete setting if the setting was not existed before testing. */ private fun resetSettings(names: Array, type: String, values: Array) { for (i in names.indices) { if (Objects.equals(values[i], null)) { instrumentation.uiAutomation.executeShellCommand( "settings delete $type ${names[i]}") } else { if (settingsTypeSecure.equals(type)) { Settings.Secure.putString(resolver, names[i], values[i]) } else { Settings.Global.putString(resolver, names[i], values[i]) } } } } fun testIntSetting( names: Array, type: String, value1: T, value2: T, getter: () -> T, setter: (value: T) -> Unit, testIntValues: IntArray ) { val originals: Array = Array(names.size) { i -> if (settingsTypeSecure.equals(type)) { Settings.Secure.getString(resolver, names[i]) } else { Settings.Global.getString(resolver, names[i]) } } try { for (i in names.indices) { if (settingsTypeSecure.equals(type)) { Settings.Secure.putString(resolver, names[i], testIntValues[i].toString()) } else { Settings.Global.putString(resolver, names[i], testIntValues[i].toString()) } } assertEquals(value1, getter()) setter(value2) assertEquals(value2, getter()) } finally { resetSettings(names, type, originals) } } @Test fun testMobileDataActivityTimeout() { testIntSetting(names = arrayOf(DATA_ACTIVITY_TIMEOUT_MOBILE), type = settingsTypeGlobal, value1 = Duration.ofSeconds(testTime1), value2 = Duration.ofSeconds(testTime2), getter = { getMobileDataActivityTimeout(context, defaultDuration) }, setter = { setMobileDataActivityTimeout(context, it) }, testIntValues = intArrayOf(testTime1.toInt())) } @Test fun testWifiDataActivityTimeout() { testIntSetting(names = arrayOf(DATA_ACTIVITY_TIMEOUT_WIFI), type = settingsTypeGlobal, value1 = Duration.ofSeconds(testTime1), value2 = Duration.ofSeconds(testTime2), getter = { getWifiDataActivityTimeout(context, defaultDuration) }, setter = { setWifiDataActivityTimeout(context, it) }, testIntValues = intArrayOf(testTime1.toInt())) } @Test fun testDnsResolverSampleValidityDuration() { testIntSetting(names = arrayOf(DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS), type = settingsTypeGlobal, value1 = Duration.ofSeconds(testTime1), value2 = Duration.ofSeconds(testTime2), getter = { getDnsResolverSampleValidityDuration(context, defaultDuration) }, setter = { setDnsResolverSampleValidityDuration(context, it) }, testIntValues = intArrayOf(testTime1.toInt())) assertFailsWith("Expect fail but argument accepted.") { setDnsResolverSampleValidityDuration(context, Duration.ofSeconds(-1L)) } } @Test fun testDnsResolverSuccessThresholdPercent() { testIntSetting(names = arrayOf(DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT), type = settingsTypeGlobal, value1 = 5, value2 = 10, getter = { getDnsResolverSuccessThresholdPercent(context, 0 /* def */) }, setter = { setDnsResolverSuccessThresholdPercent(context, it) }, testIntValues = intArrayOf(5)) assertFailsWith("Expect fail but argument accepted.") { setDnsResolverSuccessThresholdPercent(context, -1) } assertFailsWith("Expect fail but argument accepted.") { setDnsResolverSuccessThresholdPercent(context, 120) } } @Test fun testDnsResolverSampleRanges() { testIntSetting(names = arrayOf(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_MAX_SAMPLES), type = settingsTypeGlobal, value1 = Range(1, 63), value2 = Range(2, 62), getter = { getDnsResolverSampleRanges(context) }, setter = { setDnsResolverSampleRanges(context, it) }, testIntValues = intArrayOf(1, 63)) assertFailsWith("Expect fail but argument accepted.") { setDnsResolverSampleRanges(context, Range(-1, 62)) } assertFailsWith("Expect fail but argument accepted.") { setDnsResolverSampleRanges(context, Range(2, 65)) } } @Test fun testNetworkSwitchNotificationMaximumDailyCount() { testIntSetting(names = arrayOf(NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT), type = settingsTypeGlobal, value1 = 5, value2 = 15, getter = { getNetworkSwitchNotificationMaximumDailyCount(context, 0 /* def */) }, setter = { setNetworkSwitchNotificationMaximumDailyCount(context, it) }, testIntValues = intArrayOf(5)) assertFailsWith("Expect fail but argument accepted.") { setNetworkSwitchNotificationMaximumDailyCount(context, -1) } } @Test fun testNetworkSwitchNotificationRateDuration() { testIntSetting(names = arrayOf(NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS), type = settingsTypeGlobal, value1 = Duration.ofMillis(testTime1), value2 = Duration.ofMillis(testTime2), getter = { getNetworkSwitchNotificationRateDuration(context, defaultDuration) }, setter = { setNetworkSwitchNotificationRateDuration(context, it) }, testIntValues = intArrayOf(testTime1.toInt())) assertFailsWith("Expect fail but argument accepted.") { setNetworkSwitchNotificationRateDuration(context, Duration.ofMillis(-1L)) } } @Test fun testCaptivePortalMode() { testIntSetting(names = arrayOf(CAPTIVE_PORTAL_MODE), type = settingsTypeGlobal, value1 = CAPTIVE_PORTAL_MODE_AVOID, value2 = CAPTIVE_PORTAL_MODE_PROMPT, getter = { getCaptivePortalMode(context, CAPTIVE_PORTAL_MODE_IGNORE) }, setter = { setCaptivePortalMode(context, it) }, testIntValues = intArrayOf(CAPTIVE_PORTAL_MODE_AVOID)) assertFailsWith("Expect fail but argument accepted.") { setCaptivePortalMode(context, 5 /* mode */) } } @Test fun testPrivateDnsDefaultMode() { val original = Settings.Global.getString(resolver, PRIVATE_DNS_DEFAULT_MODE) try { val mode = getPrivateDnsModeAsString(PRIVATE_DNS_MODE_OPPORTUNISTIC) Settings.Global.putString(resolver, PRIVATE_DNS_DEFAULT_MODE, mode) assertEquals(mode, getPrivateDnsDefaultMode(context)) setPrivateDnsDefaultMode(context, PRIVATE_DNS_MODE_OFF) assertEquals(getPrivateDnsModeAsString(PRIVATE_DNS_MODE_OFF), getPrivateDnsDefaultMode(context)) } finally { resetSettings(names = arrayOf(PRIVATE_DNS_DEFAULT_MODE), type = settingsTypeGlobal, values = arrayOf(original)) } assertFailsWith("Expect fail but argument accepted.") { setPrivateDnsDefaultMode(context, -1) } } @Test fun testConnectivityKeepPendingIntentDuration() { testIntSetting(names = arrayOf(CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS), type = settingsTypeSecure, value1 = Duration.ofMillis(testTime1), value2 = Duration.ofMillis(testTime2), getter = { getConnectivityKeepPendingIntentDuration(context, defaultDuration) }, setter = { setConnectivityKeepPendingIntentDuration(context, it) }, testIntValues = intArrayOf(testTime1.toInt())) assertFailsWith("Expect fail but argument accepted.") { setConnectivityKeepPendingIntentDuration(context, Duration.ofMillis(-1L)) } } @Test fun testMobileDataAlwaysOn() { testIntSetting(names = arrayOf(MOBILE_DATA_ALWAYS_ON), type = settingsTypeGlobal, value1 = false, value2 = true, getter = { getMobileDataAlwaysOn(context, true /* def */) }, setter = { setMobileDataAlwaysOn(context, it) }, testIntValues = intArrayOf(0)) } @Test fun testWifiAlwaysRequested() { testIntSetting(names = arrayOf(WIFI_ALWAYS_REQUESTED), type = settingsTypeGlobal, value1 = false, value2 = true, getter = { getWifiAlwaysRequested(context, true /* def */) }, setter = { setWifiAlwaysRequested(context, it) }, testIntValues = intArrayOf(0)) } @ConnectivityModuleTest // get/setIngressRateLimitInBytesPerSecond was added via module update @Test fun testInternetNetworkRateLimitInBytesPerSecond() { val defaultRate = getIngressRateLimitInBytesPerSecond(context) val testRate = 1000L setIngressRateLimitInBytesPerSecond(context, testRate) assertEquals(testRate, getIngressRateLimitInBytesPerSecond(context)) setIngressRateLimitInBytesPerSecond(context, defaultRate) assertEquals(defaultRate, getIngressRateLimitInBytesPerSecond(context)) assertFailsWith("Expected failure, but setting accepted") { setIngressRateLimitInBytesPerSecond(context, -10) } } }