1 /*
<lambda>null2  * Copyright (C) 2023 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 com.android.systemui.statusbar.pipeline.mobile.data.repository
18 
19 import android.content.Intent
20 import android.os.PersistableBundle
21 import android.telephony.CarrierConfigManager
22 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
23 import androidx.test.ext.junit.runners.AndroidJUnit4
24 import androidx.test.filters.SmallTest
25 import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
26 import com.android.systemui.SysuiTestCase
27 import com.android.systemui.dump.DumpManager
28 import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
29 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
30 import com.android.systemui.util.mockito.whenever
31 import com.google.common.truth.Truth.assertThat
32 import kotlinx.coroutines.ExperimentalCoroutinesApi
33 import kotlinx.coroutines.flow.launchIn
34 import kotlinx.coroutines.flow.onEach
35 import kotlinx.coroutines.test.TestScope
36 import kotlinx.coroutines.test.UnconfinedTestDispatcher
37 import kotlinx.coroutines.test.runTest
38 import org.junit.After
39 import org.junit.Before
40 import org.junit.Test
41 import org.junit.runner.RunWith
42 import org.mockito.ArgumentMatchers.anyInt
43 import org.mockito.Mock
44 import org.mockito.MockitoAnnotations
45 import org.mockito.MockitoSession
46 import org.mockito.quality.Strictness
47 
48 @OptIn(ExperimentalCoroutinesApi::class)
49 @SmallTest
50 @RunWith(AndroidJUnit4::class)
51 class CarrierConfigRepositoryTest : SysuiTestCase() {
52     private val testDispatcher = UnconfinedTestDispatcher()
53     private val testScope = TestScope(testDispatcher)
54 
55     private lateinit var underTest: CarrierConfigRepository
56     private lateinit var mockitoSession: MockitoSession
57     private lateinit var carrierConfigCoreStartable: CarrierConfigCoreStartable
58 
59     @Mock private lateinit var logger: MobileInputLogger
60     @Mock private lateinit var carrierConfigManager: CarrierConfigManager
61     @Mock private lateinit var dumpManager: DumpManager
62 
63     @Before
64     fun setUp() {
65         MockitoAnnotations.initMocks(this)
66         mockitoSession =
67             mockitoSession()
68                 .initMocks(this)
69                 .mockStatic(CarrierConfigManager::class.java)
70                 .strictness(Strictness.LENIENT)
71                 .startMocking()
72 
73         whenever(CarrierConfigManager.getDefaultConfig()).thenReturn(DEFAULT_CONFIG)
74 
75         whenever(carrierConfigManager.getConfigForSubId(anyInt())).thenAnswer { invocation ->
76             when (invocation.getArgument(0) as Int) {
77                 1 -> CONFIG_1
78                 2 -> CONFIG_2
79                 else -> null
80             }
81         }
82 
83         underTest =
84             CarrierConfigRepository(
85                 fakeBroadcastDispatcher,
86                 carrierConfigManager,
87                 dumpManager,
88                 logger,
89                 testScope.backgroundScope,
90             )
91 
92         carrierConfigCoreStartable =
93             CarrierConfigCoreStartable(underTest, testScope.backgroundScope)
94     }
95 
96     @After
97     fun tearDown() {
98         mockitoSession.finishMocking()
99     }
100 
101     @Test
102     fun carrierConfigStreamProducesIntBundlePairs() =
103         testScope.runTest {
104             var latest: Pair<Int, PersistableBundle>? = null
105             val job = underTest.carrierConfigStream.onEach { latest = it }.launchIn(this)
106 
107             sendConfig(SUB_ID_1)
108             assertThat(latest).isEqualTo(Pair(SUB_ID_1, CONFIG_1))
109 
110             sendConfig(SUB_ID_2)
111             assertThat(latest).isEqualTo(Pair(SUB_ID_2, CONFIG_2))
112 
113             job.cancel()
114         }
115 
116     @Test
117     fun carrierConfigStreamIgnoresInvalidSubscriptions() =
118         testScope.runTest {
119             var latest: Pair<Int, PersistableBundle>? = null
120             val job = underTest.carrierConfigStream.onEach { latest = it }.launchIn(this)
121 
122             sendConfig(INVALID_SUBSCRIPTION_ID)
123 
124             assertThat(latest).isNull()
125 
126             job.cancel()
127         }
128 
129     @Test
130     fun getOrCreateConfig_usesDefaultConfigIfNoOverride() {
131         val config = underTest.getOrCreateConfigForSubId(123)
132         assertThat(config.isUsingDefault).isTrue()
133     }
134 
135     @Test
136     fun getOrCreateConfig_usesOverrideIfExists() {
137         val config = underTest.getOrCreateConfigForSubId(SUB_ID_1)
138         assertThat(config.isUsingDefault).isFalse()
139     }
140 
141     @Test
142     fun config_updatesWhileConfigStreamIsCollected() =
143         testScope.runTest {
144             CONFIG_1.putBoolean(CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
145 
146             carrierConfigCoreStartable.start()
147 
148             val config = underTest.getOrCreateConfigForSubId(SUB_ID_1)
149             assertThat(config.shouldInflateSignalStrength.value).isFalse()
150 
151             CONFIG_1.putBoolean(CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
152             sendConfig(SUB_ID_1)
153 
154             assertThat(config.shouldInflateSignalStrength.value).isTrue()
155         }
156 
157     private fun sendConfig(subId: Int) {
158         fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
159             context,
160             Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)
161                 .putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, subId),
162         )
163     }
164 
165     companion object {
166         private const val SUB_ID_1 = 1
167         private const val SUB_ID_2 = 2
168 
169         private val DEFAULT_CONFIG = createTestConfig()
170         private val CONFIG_1 = createTestConfig()
171         private val CONFIG_2 = createTestConfig()
172     }
173 }
174