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.util
18 
19 import android.content.Context
20 import android.content.res.Resources
21 import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER
22 import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE
23 import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY
24 import android.net.ConnectivityResources
25 import android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI
26 import android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE
27 import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdListener
28 import android.os.Build
29 import android.provider.Settings
30 import android.telephony.SubscriptionInfo
31 import android.telephony.SubscriptionManager
32 import android.telephony.TelephonyManager
33 import android.test.mock.MockContentResolver
34 import androidx.test.filters.SmallTest
35 import com.android.connectivity.resources.R
36 import com.android.internal.util.test.FakeSettingsProvider
37 import com.android.testutils.DevSdkIgnoreRule
38 import com.android.testutils.DevSdkIgnoreRunner
39 import org.junit.After
40 import org.junit.Assert.assertEquals
41 import org.junit.Assert.assertFalse
42 import org.junit.Assert.assertTrue
43 import org.junit.Test
44 import org.junit.runner.RunWith
45 import org.mockito.ArgumentCaptor
46 import org.mockito.ArgumentMatchers.anyInt
47 import org.mockito.ArgumentMatchers.argThat
48 import org.mockito.ArgumentMatchers.eq
49 import org.mockito.Mockito.any
50 import org.mockito.Mockito.doCallRealMethod
51 import org.mockito.Mockito.doReturn
52 import org.mockito.Mockito.mock
53 import org.mockito.Mockito.times
54 import org.mockito.Mockito.verify
55 
56 /**
57  * Tests for [MultinetworkPolicyTracker].
58  *
59  * Build, install and run with:
60  * atest android.net.util.MultinetworkPolicyTrackerTest
61  */
62 @RunWith(DevSdkIgnoreRunner::class)
63 @SmallTest
64 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
65 class MultinetworkPolicyTrackerTest {
66     private val resources = mock(Resources::class.java).also {
67         doReturn(R.integer.config_networkAvoidBadWifi).`when`(it).getIdentifier(
68                 eq("config_networkAvoidBadWifi"), eq("integer"), any())
69         doReturn(0).`when`(it).getInteger(R.integer.config_networkAvoidBadWifi)
70     }
71     private val telephonyManager = mock(TelephonyManager::class.java)
72     private val subscriptionManager = mock(SubscriptionManager::class.java).also {
73         doReturn(null).`when`(it).getActiveSubscriptionInfo(anyInt())
74     }
75     private val resolver = MockContentResolver().apply {
76         addProvider(Settings.AUTHORITY, FakeSettingsProvider()) }
77     private val context = mock(Context::class.java).also {
78         doReturn(Context.TELEPHONY_SERVICE).`when`(it)
79                 .getSystemServiceName(TelephonyManager::class.java)
80         doReturn(telephonyManager).`when`(it).getSystemService(Context.TELEPHONY_SERVICE)
81         if (it.getSystemService(TelephonyManager::class.java) == null) {
82             // Test is using mockito extended
83             doCallRealMethod().`when`(it).getSystemService(TelephonyManager::class.java)
84         }
85         doReturn(subscriptionManager).`when`(it)
86                 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
87         doReturn(resolver).`when`(it).contentResolver
88         doReturn(resources).`when`(it).resources
89         doReturn(it).`when`(it).createConfigurationContext(any())
90         Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1")
91         ConnectivityResources.setResourcesContextForTest(it)
92     }
93     private val tracker = MultinetworkPolicyTracker(context, null /* handler */)
94 
95     private fun assertMultipathPreference(preference: Int) {
96         Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
97                 preference.toString())
98         tracker.updateMeteredMultipathPreference()
99         assertEquals(preference, tracker.meteredMultipathPreference)
100     }
101 
102     @After
103     fun tearDown() {
104         ConnectivityResources.setResourcesContextForTest(null)
105     }
106 
107     @Test
108     fun testUpdateMeteredMultipathPreference() {
109         assertMultipathPreference(MULTIPATH_PREFERENCE_HANDOVER)
110         assertMultipathPreference(MULTIPATH_PREFERENCE_RELIABILITY)
111         assertMultipathPreference(MULTIPATH_PREFERENCE_PERFORMANCE)
112     }
113 
114     @Test
115     fun testUpdateAvoidBadWifi() {
116         Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
117         assertTrue(tracker.updateAvoidBadWifi())
118         assertFalse(tracker.avoidBadWifi)
119 
120         doReturn(1).`when`(resources).getInteger(R.integer.config_networkAvoidBadWifi)
121         assertTrue(tracker.updateAvoidBadWifi())
122         assertTrue(tracker.avoidBadWifi)
123     }
124 
125     @Test
126     fun testOnActiveDataSubscriptionIdChanged() {
127         val testSubId = 1000
128         val subscriptionInfo = SubscriptionInfo(testSubId, ""/* iccId */, 1/* iccId */,
129                 "TMO"/* displayName */, "TMO"/* carrierName */, 1/* nameSource */, 1/* iconTint */,
130                 "123"/* number */, 1/* roaming */, null/* icon */, "310"/* mcc */, "210"/* mnc */,
131                 ""/* countryIso */, false/* isEmbedded */, null/* nativeAccessRules */,
132                 "1"/* cardString */)
133         doReturn(subscriptionInfo).`when`(subscriptionManager).getActiveSubscriptionInfo(testSubId)
134 
135         // Modify avoidBadWifi and meteredMultipathPreference settings value and local variables in
136         // MultinetworkPolicyTracker should be also updated after subId changed.
137         Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
138         Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
139                 MULTIPATH_PREFERENCE_PERFORMANCE.toString())
140 
141         val listenerCaptor = ArgumentCaptor.forClass(
142                 ActiveDataSubscriptionIdListener::class.java)
143         verify(telephonyManager, times(1))
144                 .registerTelephonyCallback(any(), listenerCaptor.capture())
145         val listener = listenerCaptor.value
146         listener.onActiveDataSubscriptionIdChanged(testSubId)
147 
148         // Check it get resource value with test sub id.
149         verify(subscriptionManager, times(1)).getActiveSubscriptionInfo(testSubId)
150         verify(context).createConfigurationContext(argThat { it.mcc == 310 && it.mnc == 210 })
151 
152         // Check if avoidBadWifi and meteredMultipathPreference values have been updated.
153         assertFalse(tracker.avoidBadWifi)
154         assertEquals(MULTIPATH_PREFERENCE_PERFORMANCE, tracker.meteredMultipathPreference)
155     }
156 }
157