1 /* 2 * Copyright (C) 2021 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 android.net 18 19 import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE 20 import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID 21 import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_IGNORE 22 import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT 23 import android.net.ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS 24 import android.net.ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_MOBILE 25 import android.net.ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_WIFI 26 import android.net.ConnectivitySettingsManager.DNS_RESOLVER_MAX_SAMPLES 27 import android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES 28 import android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS 29 import android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT 30 import android.net.ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON 31 import android.net.ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT 32 import android.net.ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS 33 import android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE 34 import android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF 35 import android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC 36 import android.net.ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED 37 import android.net.ConnectivitySettingsManager.getCaptivePortalMode 38 import android.net.ConnectivitySettingsManager.getConnectivityKeepPendingIntentDuration 39 import android.net.ConnectivitySettingsManager.getDnsResolverSampleRanges 40 import android.net.ConnectivitySettingsManager.getDnsResolverSampleValidityDuration 41 import android.net.ConnectivitySettingsManager.getDnsResolverSuccessThresholdPercent 42 import android.net.ConnectivitySettingsManager.getMobileDataActivityTimeout 43 import android.net.ConnectivitySettingsManager.getMobileDataAlwaysOn 44 import android.net.ConnectivitySettingsManager.getNetworkSwitchNotificationMaximumDailyCount 45 import android.net.ConnectivitySettingsManager.getNetworkSwitchNotificationRateDuration 46 import android.net.ConnectivitySettingsManager.getPrivateDnsDefaultMode 47 import android.net.ConnectivitySettingsManager.getWifiAlwaysRequested 48 import android.net.ConnectivitySettingsManager.getWifiDataActivityTimeout 49 import android.net.ConnectivitySettingsManager.setCaptivePortalMode 50 import android.net.ConnectivitySettingsManager.setConnectivityKeepPendingIntentDuration 51 import android.net.ConnectivitySettingsManager.setDnsResolverSampleRanges 52 import android.net.ConnectivitySettingsManager.setDnsResolverSampleValidityDuration 53 import android.net.ConnectivitySettingsManager.setDnsResolverSuccessThresholdPercent 54 import android.net.ConnectivitySettingsManager.setMobileDataActivityTimeout 55 import android.net.ConnectivitySettingsManager.setMobileDataAlwaysOn 56 import android.net.ConnectivitySettingsManager.setNetworkSwitchNotificationMaximumDailyCount 57 import android.net.ConnectivitySettingsManager.setNetworkSwitchNotificationRateDuration 58 import android.net.ConnectivitySettingsManager.setPrivateDnsDefaultMode 59 import android.net.ConnectivitySettingsManager.setWifiAlwaysRequested 60 import android.net.ConnectivitySettingsManager.setWifiDataActivityTimeout 61 import android.os.Build 62 import android.platform.test.annotations.AppModeFull 63 import android.provider.Settings 64 import android.util.Range 65 import androidx.test.InstrumentationRegistry 66 import androidx.test.filters.SmallTest 67 import com.android.net.module.util.ConnectivitySettingsUtils.getPrivateDnsModeAsString 68 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo 69 import com.android.testutils.DevSdkIgnoreRunner 70 import junit.framework.Assert.assertEquals 71 import org.junit.Test 72 import org.junit.runner.RunWith 73 import java.time.Duration 74 import java.util.Objects 75 import kotlin.test.assertFailsWith 76 77 /** 78 * Tests for [ConnectivitySettingsManager]. 79 * 80 * Build, install and run with: 81 * atest android.net.ConnectivitySettingsManagerTest 82 */ 83 @RunWith(DevSdkIgnoreRunner::class) 84 @IgnoreUpTo(Build.VERSION_CODES.R) 85 @SmallTest 86 @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") 87 class ConnectivitySettingsManagerTest { 88 private val instrumentation = InstrumentationRegistry.getInstrumentation() 89 private val context = instrumentation.context 90 private val resolver = context.contentResolver 91 92 private val defaultDuration = Duration.ofSeconds(0L) 93 private val testTime1 = 5L 94 private val testTime2 = 10L 95 private val settingsTypeGlobal = "global" 96 private val settingsTypeSecure = "secure" 97 98 /*** Reset setting value or delete setting if the setting was not existed before testing. */ 99 private fun resetSettings(names: Array<String>, type: String, values: Array<String?>) { 100 for (i in names.indices) { 101 if (Objects.equals(values[i], null)) { 102 instrumentation.uiAutomation.executeShellCommand( 103 "settings delete $type ${names[i]}") 104 } else { 105 if (settingsTypeSecure.equals(type)) { 106 Settings.Secure.putString(resolver, names[i], values[i]) 107 } else { 108 Settings.Global.putString(resolver, names[i], values[i]) 109 } 110 } 111 } 112 } 113 114 fun <T> testIntSetting( 115 names: Array<String>, 116 type: String, 117 value1: T, 118 value2: T, 119 getter: () -> T, 120 setter: (value: T) -> Unit, 121 testIntValues: IntArray 122 ) { 123 val originals: Array<String?> = Array(names.size) { i -> 124 if (settingsTypeSecure.equals(type)) { 125 Settings.Secure.getString(resolver, names[i]) 126 } else { 127 Settings.Global.getString(resolver, names[i]) 128 } 129 } 130 131 try { 132 for (i in names.indices) { 133 if (settingsTypeSecure.equals(type)) { 134 Settings.Secure.putString(resolver, names[i], testIntValues[i].toString()) 135 } else { 136 Settings.Global.putString(resolver, names[i], testIntValues[i].toString()) 137 } 138 } 139 assertEquals(value1, getter()) 140 141 setter(value2) 142 assertEquals(value2, getter()) 143 } finally { 144 resetSettings(names, type, originals) 145 } 146 } 147 148 @Test 149 fun testMobileDataActivityTimeout() { 150 testIntSetting(names = arrayOf(DATA_ACTIVITY_TIMEOUT_MOBILE), type = settingsTypeGlobal, 151 value1 = Duration.ofSeconds(testTime1), value2 = Duration.ofSeconds(testTime2), 152 getter = { getMobileDataActivityTimeout(context, defaultDuration) }, 153 setter = { setMobileDataActivityTimeout(context, it) }, 154 testIntValues = intArrayOf(testTime1.toInt())) 155 } 156 157 @Test 158 fun testWifiDataActivityTimeout() { 159 testIntSetting(names = arrayOf(DATA_ACTIVITY_TIMEOUT_WIFI), type = settingsTypeGlobal, 160 value1 = Duration.ofSeconds(testTime1), value2 = Duration.ofSeconds(testTime2), 161 getter = { getWifiDataActivityTimeout(context, defaultDuration) }, 162 setter = { setWifiDataActivityTimeout(context, it) }, 163 testIntValues = intArrayOf(testTime1.toInt())) 164 } 165 166 @Test 167 fun testDnsResolverSampleValidityDuration() { 168 testIntSetting(names = arrayOf(DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS), 169 type = settingsTypeGlobal, value1 = Duration.ofSeconds(testTime1), 170 value2 = Duration.ofSeconds(testTime2), 171 getter = { getDnsResolverSampleValidityDuration(context, defaultDuration) }, 172 setter = { setDnsResolverSampleValidityDuration(context, it) }, 173 testIntValues = intArrayOf(testTime1.toInt())) 174 175 assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") { 176 setDnsResolverSampleValidityDuration(context, Duration.ofSeconds(-1L)) } 177 } 178 179 @Test 180 fun testDnsResolverSuccessThresholdPercent() { 181 testIntSetting(names = arrayOf(DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT), 182 type = settingsTypeGlobal, value1 = 5, value2 = 10, 183 getter = { getDnsResolverSuccessThresholdPercent(context, 0 /* def */) }, 184 setter = { setDnsResolverSuccessThresholdPercent(context, it) }, 185 testIntValues = intArrayOf(5)) 186 187 assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") { 188 setDnsResolverSuccessThresholdPercent(context, -1) } 189 assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") { 190 setDnsResolverSuccessThresholdPercent(context, 120) } 191 } 192 193 @Test 194 fun testDnsResolverSampleRanges() { 195 testIntSetting(names = arrayOf(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_MAX_SAMPLES), 196 type = settingsTypeGlobal, value1 = Range(1, 63), value2 = Range(2, 62), 197 getter = { getDnsResolverSampleRanges(context) }, 198 setter = { setDnsResolverSampleRanges(context, it) }, 199 testIntValues = intArrayOf(1, 63)) 200 201 assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") { 202 setDnsResolverSampleRanges(context, Range(-1, 62)) } 203 assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") { 204 setDnsResolverSampleRanges(context, Range(2, 65)) } 205 } 206 207 @Test 208 fun testNetworkSwitchNotificationMaximumDailyCount() { 209 testIntSetting(names = arrayOf(NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT), 210 type = settingsTypeGlobal, value1 = 5, value2 = 15, 211 getter = { getNetworkSwitchNotificationMaximumDailyCount(context, 0 /* def */) }, 212 setter = { setNetworkSwitchNotificationMaximumDailyCount(context, it) }, 213 testIntValues = intArrayOf(5)) 214 215 assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") { 216 setNetworkSwitchNotificationMaximumDailyCount(context, -1) } 217 } 218 219 @Test 220 fun testNetworkSwitchNotificationRateDuration() { 221 testIntSetting(names = arrayOf(NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS), 222 type = settingsTypeGlobal, value1 = Duration.ofMillis(testTime1), 223 value2 = Duration.ofMillis(testTime2), 224 getter = { getNetworkSwitchNotificationRateDuration(context, defaultDuration) }, 225 setter = { setNetworkSwitchNotificationRateDuration(context, it) }, 226 testIntValues = intArrayOf(testTime1.toInt())) 227 228 assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") { 229 setNetworkSwitchNotificationRateDuration(context, Duration.ofMillis(-1L)) } 230 } 231 232 @Test 233 fun testCaptivePortalMode() { 234 testIntSetting(names = arrayOf(CAPTIVE_PORTAL_MODE), type = settingsTypeGlobal, 235 value1 = CAPTIVE_PORTAL_MODE_AVOID, value2 = CAPTIVE_PORTAL_MODE_PROMPT, 236 getter = { getCaptivePortalMode(context, CAPTIVE_PORTAL_MODE_IGNORE) }, 237 setter = { setCaptivePortalMode(context, it) }, 238 testIntValues = intArrayOf(CAPTIVE_PORTAL_MODE_AVOID)) 239 240 assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") { 241 setCaptivePortalMode(context, 5 /* mode */) } 242 } 243 244 @Test 245 fun testPrivateDnsDefaultMode() { 246 val original = Settings.Global.getString(resolver, PRIVATE_DNS_DEFAULT_MODE) 247 248 try { 249 val mode = getPrivateDnsModeAsString(PRIVATE_DNS_MODE_OPPORTUNISTIC) 250 Settings.Global.putString(resolver, PRIVATE_DNS_DEFAULT_MODE, mode) 251 assertEquals(mode, getPrivateDnsDefaultMode(context)) 252 253 setPrivateDnsDefaultMode(context, PRIVATE_DNS_MODE_OFF) 254 assertEquals(getPrivateDnsModeAsString(PRIVATE_DNS_MODE_OFF), 255 getPrivateDnsDefaultMode(context)) 256 } finally { 257 resetSettings(names = arrayOf(PRIVATE_DNS_DEFAULT_MODE), type = settingsTypeGlobal, 258 values = arrayOf(original)) 259 } 260 261 assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") { 262 setPrivateDnsDefaultMode(context, -1) } 263 } 264 265 @Test 266 fun testConnectivityKeepPendingIntentDuration() { 267 testIntSetting(names = arrayOf(CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS), 268 type = settingsTypeSecure, value1 = Duration.ofMillis(testTime1), 269 value2 = Duration.ofMillis(testTime2), 270 getter = { getConnectivityKeepPendingIntentDuration(context, defaultDuration) }, 271 setter = { setConnectivityKeepPendingIntentDuration(context, it) }, 272 testIntValues = intArrayOf(testTime1.toInt())) 273 274 assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") { 275 setConnectivityKeepPendingIntentDuration(context, Duration.ofMillis(-1L)) } 276 } 277 278 @Test 279 fun testMobileDataAlwaysOn() { 280 testIntSetting(names = arrayOf(MOBILE_DATA_ALWAYS_ON), type = settingsTypeGlobal, 281 value1 = false, value2 = true, 282 getter = { getMobileDataAlwaysOn(context, true /* def */) }, 283 setter = { setMobileDataAlwaysOn(context, it) }, 284 testIntValues = intArrayOf(0)) 285 } 286 287 @Test 288 fun testWifiAlwaysRequested() { 289 testIntSetting(names = arrayOf(WIFI_ALWAYS_REQUESTED), type = settingsTypeGlobal, 290 value1 = false, value2 = true, 291 getter = { getWifiAlwaysRequested(context, true /* def */) }, 292 setter = { setWifiAlwaysRequested(context, it) }, 293 testIntValues = intArrayOf(0)) 294 } 295 }