1 /*
<lambda>null2 * Copyright (C) 2022 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.demo
18
19 import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
20 import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
21 import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID
22 import androidx.test.ext.junit.runners.AndroidJUnit4
23 import androidx.test.filters.SmallTest
24 import com.android.settingslib.SignalIcon
25 import com.android.settingslib.mobile.TelephonyIcons.THREE_G
26 import com.android.systemui.SysuiTestCase
27 import com.android.systemui.log.table.tableLogBufferFactory
28 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
29 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
30 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
31 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
32 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
33 import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
34 import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
35 import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
36 import com.android.systemui.testKosmos
37 import com.android.systemui.util.mockito.mock
38 import com.android.systemui.util.mockito.whenever
39 import com.google.common.truth.Truth.assertThat
40 import junit.framework.Assert
41 import kotlinx.coroutines.ExperimentalCoroutinesApi
42 import kotlinx.coroutines.Job
43 import kotlinx.coroutines.flow.MutableStateFlow
44 import kotlinx.coroutines.flow.launchIn
45 import kotlinx.coroutines.flow.onEach
46 import kotlinx.coroutines.launch
47 import kotlinx.coroutines.test.TestScope
48 import kotlinx.coroutines.test.UnconfinedTestDispatcher
49 import kotlinx.coroutines.test.runTest
50 import org.junit.Before
51 import org.junit.Test
52 import org.junit.runner.RunWith
53
54 @OptIn(ExperimentalCoroutinesApi::class)
55 @SmallTest
56 @RunWith(AndroidJUnit4::class)
57 class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
58 private val kosmos = testKosmos()
59
60 private val testDispatcher = UnconfinedTestDispatcher()
61 private val testScope = TestScope(testDispatcher)
62
63 private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
64 private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null)
65
66 private lateinit var underTest: DemoMobileConnectionsRepository
67 private lateinit var mobileDataSource: DemoModeMobileConnectionDataSource
68 private lateinit var wifiDataSource: DemoModeWifiDataSource
69
70 @Before
71 fun setUp() {
72 // The data source only provides one API, so we can mock it with a flow here for convenience
73 mobileDataSource =
74 mock<DemoModeMobileConnectionDataSource>().also {
75 whenever(it.mobileEvents).thenReturn(fakeNetworkEventFlow)
76 }
77 wifiDataSource =
78 mock<DemoModeWifiDataSource>().also {
79 whenever(it.wifiEvents).thenReturn(fakeWifiEventFlow)
80 }
81
82 underTest =
83 DemoMobileConnectionsRepository(
84 mobileDataSource = mobileDataSource,
85 wifiDataSource = wifiDataSource,
86 scope = testScope.backgroundScope,
87 context = context,
88 logFactory = kosmos.tableLogBufferFactory,
89 )
90
91 underTest.startProcessingCommands()
92 }
93
94 @Test
95 fun isDefault_defaultsToTrue() =
96 testScope.runTest {
97 val isDefault = underTest.mobileIsDefault.value
98 assertThat(isDefault).isTrue()
99 }
100
101 @Test
102 fun validated_defaultsToTrue() =
103 testScope.runTest {
104 val isValidated = underTest.defaultConnectionIsValidated.value
105 assertThat(isValidated).isTrue()
106 }
107
108 @Test
109 fun networkEvent_createNewSubscription() =
110 testScope.runTest {
111 var latest: List<SubscriptionModel>? = null
112 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
113
114 assertThat(latest).isEmpty()
115
116 fakeNetworkEventFlow.value = validMobileEvent(subId = 1)
117
118 assertThat(latest).hasSize(1)
119 assertThat(latest!![0].subscriptionId).isEqualTo(1)
120
121 job.cancel()
122 }
123
124 @Test
125 fun wifiCarrierMergedEvent_createNewSubscription() =
126 testScope.runTest {
127 var latest: List<SubscriptionModel>? = null
128 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
129
130 assertThat(latest).isEmpty()
131
132 fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5)
133
134 assertThat(latest).hasSize(1)
135 assertThat(latest!![0].subscriptionId).isEqualTo(5)
136
137 job.cancel()
138 }
139
140 @Test
141 fun networkEvent_reusesSubscriptionWhenSameId() =
142 testScope.runTest {
143 var latest: List<SubscriptionModel>? = null
144 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
145
146 assertThat(latest).isEmpty()
147
148 fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1)
149
150 assertThat(latest).hasSize(1)
151 assertThat(latest!![0].subscriptionId).isEqualTo(1)
152
153 // Second network event comes in with the same subId, does not create a new subscription
154 fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 2)
155
156 assertThat(latest).hasSize(1)
157 assertThat(latest!![0].subscriptionId).isEqualTo(1)
158
159 job.cancel()
160 }
161
162 @Test
163 fun wifiCarrierMergedEvent_reusesSubscriptionWhenSameId() =
164 testScope.runTest {
165 var latest: List<SubscriptionModel>? = null
166 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
167
168 assertThat(latest).isEmpty()
169
170 fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5, level = 1)
171
172 assertThat(latest).hasSize(1)
173 assertThat(latest!![0].subscriptionId).isEqualTo(5)
174
175 // Second network event comes in with the same subId, does not create a new subscription
176 fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5, level = 2)
177
178 assertThat(latest).hasSize(1)
179 assertThat(latest!![0].subscriptionId).isEqualTo(5)
180
181 job.cancel()
182 }
183
184 @Test
185 fun multipleSubscriptions() =
186 testScope.runTest {
187 var latest: List<SubscriptionModel>? = null
188 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
189
190 fakeNetworkEventFlow.value = validMobileEvent(subId = 1)
191 fakeNetworkEventFlow.value = validMobileEvent(subId = 2)
192
193 assertThat(latest).hasSize(2)
194
195 job.cancel()
196 }
197
198 @Test
199 fun mobileSubscriptionAndCarrierMergedSubscription() =
200 testScope.runTest {
201 var latest: List<SubscriptionModel>? = null
202 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
203
204 fakeNetworkEventFlow.value = validMobileEvent(subId = 1)
205 fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5)
206
207 assertThat(latest).hasSize(2)
208
209 job.cancel()
210 }
211
212 @Test
213 fun multipleMobileSubscriptionsAndCarrierMergedSubscription() =
214 testScope.runTest {
215 var latest: List<SubscriptionModel>? = null
216 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
217
218 fakeNetworkEventFlow.value = validMobileEvent(subId = 1)
219 fakeNetworkEventFlow.value = validMobileEvent(subId = 2)
220 fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 3)
221
222 assertThat(latest).hasSize(3)
223
224 job.cancel()
225 }
226
227 @Test
228 fun mobileDisabledEvent_disablesConnection_subIdSpecified_singleConn() =
229 testScope.runTest {
230 var latest: List<SubscriptionModel>? = null
231 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
232
233 fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1)
234
235 fakeNetworkEventFlow.value = MobileDisabled(subId = 1)
236
237 assertThat(latest).hasSize(0)
238
239 job.cancel()
240 }
241
242 @Test
243 fun mobileDisabledEvent_disablesConnection_subIdNotSpecified_singleConn() =
244 testScope.runTest {
245 var latest: List<SubscriptionModel>? = null
246 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
247
248 fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1)
249
250 fakeNetworkEventFlow.value = MobileDisabled(subId = null)
251
252 assertThat(latest).hasSize(0)
253
254 job.cancel()
255 }
256
257 @Test
258 fun mobileDisabledEvent_disablesConnection_subIdSpecified_multipleConn() =
259 testScope.runTest {
260 var latest: List<SubscriptionModel>? = null
261 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
262
263 fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1)
264 fakeNetworkEventFlow.value = validMobileEvent(subId = 2, level = 1)
265
266 fakeNetworkEventFlow.value = MobileDisabled(subId = 2)
267
268 assertThat(latest).hasSize(1)
269
270 job.cancel()
271 }
272
273 @Test
274 fun mobileDisabledEvent_subIdNotSpecified_multipleConn_ignoresCommand() =
275 testScope.runTest {
276 var latest: List<SubscriptionModel>? = null
277 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
278
279 fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1)
280 fakeNetworkEventFlow.value = validMobileEvent(subId = 2, level = 1)
281
282 fakeNetworkEventFlow.value = MobileDisabled(subId = null)
283
284 assertThat(latest).hasSize(2)
285
286 job.cancel()
287 }
288
289 @Test
290 fun wifiNetworkUpdatesToDisabled_carrierMergedConnectionRemoved() =
291 testScope.runTest {
292 var latest: List<SubscriptionModel>? = null
293 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
294
295 fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 1)
296
297 assertThat(latest).hasSize(1)
298
299 fakeWifiEventFlow.value = FakeWifiEventModel.WifiDisabled
300
301 assertThat(latest).isEmpty()
302
303 job.cancel()
304 }
305
306 @Test
307 fun wifiNetworkUpdatesToActive_carrierMergedConnectionRemoved() =
308 testScope.runTest {
309 var latest: List<SubscriptionModel>? = null
310 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
311
312 fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 1)
313
314 assertThat(latest).hasSize(1)
315
316 fakeWifiEventFlow.value =
317 FakeWifiEventModel.Wifi(
318 level = 1,
319 activity = 0,
320 ssid = null,
321 validated = true,
322 )
323
324 assertThat(latest).isEmpty()
325
326 job.cancel()
327 }
328
329 @Test
330 fun mobileSubUpdatesToCarrierMerged_onlyOneConnection() =
331 testScope.runTest {
332 var latestSubsList: List<SubscriptionModel>? = null
333 var connections: List<DemoMobileConnectionRepository>? = null
334 val job =
335 underTest.subscriptions
336 .onEach { latestSubsList = it }
337 .onEach { infos ->
338 connections =
339 infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
340 }
341 .launchIn(this)
342
343 fakeNetworkEventFlow.value = validMobileEvent(subId = 3, level = 2)
344 assertThat(latestSubsList).hasSize(1)
345
346 val carrierMergedEvent = validCarrierMergedEvent(subId = 3, level = 1)
347 fakeWifiEventFlow.value = carrierMergedEvent
348 assertThat(latestSubsList).hasSize(1)
349 val connection = connections!!.find { it.subId == 3 }!!
350 assertCarrierMergedConnection(connection, carrierMergedEvent)
351
352 job.cancel()
353 }
354
355 @Test
356 fun mobileSubUpdatesToCarrierMergedThenBack_hasOldMobileData() =
357 testScope.runTest {
358 var latestSubsList: List<SubscriptionModel>? = null
359 var connections: List<DemoMobileConnectionRepository>? = null
360 val job =
361 underTest.subscriptions
362 .onEach { latestSubsList = it }
363 .onEach { infos ->
364 connections =
365 infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
366 }
367 .launchIn(this)
368
369 val mobileEvent = validMobileEvent(subId = 3, level = 2)
370 fakeNetworkEventFlow.value = mobileEvent
371 assertThat(latestSubsList).hasSize(1)
372
373 val carrierMergedEvent = validCarrierMergedEvent(subId = 3, level = 1)
374 fakeWifiEventFlow.value = carrierMergedEvent
375 assertThat(latestSubsList).hasSize(1)
376 var connection = connections!!.find { it.subId == 3 }!!
377 assertCarrierMergedConnection(connection, carrierMergedEvent)
378
379 // WHEN the carrier merged is removed
380 fakeWifiEventFlow.value =
381 FakeWifiEventModel.Wifi(
382 level = 4,
383 activity = 0,
384 ssid = null,
385 validated = true,
386 )
387
388 // THEN the subId=3 connection goes back to the mobile information
389 connection = connections!!.find { it.subId == 3 }!!
390 assertConnection(connection, mobileEvent)
391
392 job.cancel()
393 }
394
395 /** Regression test for b/261706421 */
396 @Test
397 fun multipleConnections_removeAll_doesNotThrow() =
398 testScope.runTest {
399 var latest: List<SubscriptionModel>? = null
400 val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
401
402 // Two subscriptions are added
403 fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1)
404 fakeNetworkEventFlow.value = validMobileEvent(subId = 2, level = 1)
405
406 // Then both are removed by turning off demo mode
407 underTest.stopProcessingCommands()
408
409 assertThat(latest).isEmpty()
410
411 job.cancel()
412 }
413
414 @Test
415 fun demoConnection_singleSubscription() =
416 testScope.runTest {
417 var currentEvent: FakeNetworkEventModel = validMobileEvent(subId = 1)
418 var connections: List<DemoMobileConnectionRepository>? = null
419 val job =
420 underTest.subscriptions
421 .onEach { infos ->
422 connections =
423 infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
424 }
425 .launchIn(this)
426
427 fakeNetworkEventFlow.value = currentEvent
428
429 assertThat(connections).hasSize(1)
430 val connection1 = connections!![0]
431
432 assertConnection(connection1, currentEvent)
433
434 // Exercise the whole api
435
436 currentEvent = validMobileEvent(subId = 1, level = 2)
437 fakeNetworkEventFlow.value = currentEvent
438 assertConnection(connection1, currentEvent)
439
440 job.cancel()
441 }
442
443 @Test
444 fun demoConnection_twoConnections_updateSecond_noAffectOnFirst() =
445 testScope.runTest {
446 var currentEvent1 = validMobileEvent(subId = 1)
447 var connection1: DemoMobileConnectionRepository? = null
448 var currentEvent2 = validMobileEvent(subId = 2)
449 var connection2: DemoMobileConnectionRepository? = null
450 var connections: List<DemoMobileConnectionRepository>? = null
451 val job =
452 underTest.subscriptions
453 .onEach { infos ->
454 connections =
455 infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
456 }
457 .launchIn(this)
458
459 fakeNetworkEventFlow.value = currentEvent1
460 fakeNetworkEventFlow.value = currentEvent2
461 assertThat(connections).hasSize(2)
462 connections!!.forEach {
463 if (it.subId == 1) {
464 connection1 = it
465 } else if (it.subId == 2) {
466 connection2 = it
467 } else {
468 Assert.fail("Unexpected subscription")
469 }
470 }
471
472 assertConnection(connection1!!, currentEvent1)
473 assertConnection(connection2!!, currentEvent2)
474
475 // WHEN the event changes for connection 2, it updates, and connection 1 stays the same
476 currentEvent2 = validMobileEvent(subId = 2, activity = DATA_ACTIVITY_INOUT)
477 fakeNetworkEventFlow.value = currentEvent2
478 assertConnection(connection1!!, currentEvent1)
479 assertConnection(connection2!!, currentEvent2)
480
481 // and vice versa
482 currentEvent1 = validMobileEvent(subId = 1, inflateStrength = true)
483 fakeNetworkEventFlow.value = currentEvent1
484 assertConnection(connection1!!, currentEvent1)
485 assertConnection(connection2!!, currentEvent2)
486
487 job.cancel()
488 }
489
490 @Test
491 fun demoConnection_twoConnections_updateCarrierMerged_noAffectOnFirst() =
492 testScope.runTest {
493 var currentEvent1 = validMobileEvent(subId = 1)
494 var connection1: DemoMobileConnectionRepository? = null
495 var currentEvent2 = validCarrierMergedEvent(subId = 2)
496 var connection2: DemoMobileConnectionRepository? = null
497 var connections: List<DemoMobileConnectionRepository>? = null
498 val job =
499 underTest.subscriptions
500 .onEach { infos ->
501 connections =
502 infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
503 }
504 .launchIn(this)
505
506 fakeNetworkEventFlow.value = currentEvent1
507 fakeWifiEventFlow.value = currentEvent2
508 assertThat(connections).hasSize(2)
509 connections!!.forEach {
510 when (it.subId) {
511 1 -> connection1 = it
512 2 -> connection2 = it
513 else -> Assert.fail("Unexpected subscription")
514 }
515 }
516
517 assertConnection(connection1!!, currentEvent1)
518 assertCarrierMergedConnection(connection2!!, currentEvent2)
519
520 // WHEN the event changes for connection 2, it updates, and connection 1 stays the same
521 currentEvent2 = validCarrierMergedEvent(subId = 2, level = 4)
522 fakeWifiEventFlow.value = currentEvent2
523 assertConnection(connection1!!, currentEvent1)
524 assertCarrierMergedConnection(connection2!!, currentEvent2)
525
526 // and vice versa
527 currentEvent1 = validMobileEvent(subId = 1, inflateStrength = true)
528 fakeNetworkEventFlow.value = currentEvent1
529 assertConnection(connection1!!, currentEvent1)
530 assertCarrierMergedConnection(connection2!!, currentEvent2)
531
532 job.cancel()
533 }
534
535 @Test
536 fun demoIsNotInEcmState() = testScope.runTest { assertThat(underTest.isInEcmMode()).isFalse() }
537
538 private fun TestScope.startCollection(conn: DemoMobileConnectionRepository): Job {
539 val job = launch {
540 launch { conn.cdmaLevel.collect {} }
541 launch { conn.primaryLevel.collect {} }
542 launch { conn.dataActivityDirection.collect {} }
543 launch { conn.carrierNetworkChangeActive.collect {} }
544 launch { conn.isRoaming.collect {} }
545 launch { conn.networkName.collect {} }
546 launch { conn.carrierName.collect {} }
547 launch { conn.isEmergencyOnly.collect {} }
548 launch { conn.dataConnectionState.collect {} }
549 launch { conn.hasPrioritizedNetworkCapabilities.collect {} }
550 }
551 return job
552 }
553
554 private fun TestScope.assertConnection(
555 conn: DemoMobileConnectionRepository,
556 model: FakeNetworkEventModel,
557 ) {
558 val job = startCollection(conn)
559 // Assert the fields using the `MutableStateFlow` so that we don't have to start up
560 // a collector for every field for every test
561 when (model) {
562 is FakeNetworkEventModel.Mobile -> {
563 assertThat(conn.subId).isEqualTo(model.subId)
564 assertThat(conn.cdmaLevel.value).isEqualTo(model.level)
565 assertThat(conn.primaryLevel.value).isEqualTo(model.level)
566 assertThat(conn.dataActivityDirection.value)
567 .isEqualTo((model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel())
568 assertThat(conn.carrierNetworkChangeActive.value)
569 .isEqualTo(model.carrierNetworkChange)
570 assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
571 assertThat(conn.networkName.value)
572 .isEqualTo(NetworkNameModel.IntentDerived(model.name))
573 assertThat(conn.carrierName.value)
574 .isEqualTo(NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}"))
575 assertThat(conn.hasPrioritizedNetworkCapabilities.value).isEqualTo(model.slice)
576 assertThat(conn.isNonTerrestrial.value).isEqualTo(model.ntn)
577
578 // TODO(b/261029387) check these once we start handling them
579 assertThat(conn.isEmergencyOnly.value).isFalse()
580 assertThat(conn.isGsm.value).isFalse()
581 assertThat(conn.dataConnectionState.value).isEqualTo(DataConnectionState.Connected)
582 }
583 else -> {}
584 }
585
586 job.cancel()
587 }
588
589 private fun TestScope.assertCarrierMergedConnection(
590 conn: DemoMobileConnectionRepository,
591 model: FakeWifiEventModel.CarrierMerged,
592 ) {
593 val job = startCollection(conn)
594 assertThat(conn.subId).isEqualTo(model.subscriptionId)
595 assertThat(conn.cdmaLevel.value).isEqualTo(model.level)
596 assertThat(conn.primaryLevel.value).isEqualTo(model.level)
597 assertThat(conn.carrierNetworkChangeActive.value).isEqualTo(false)
598 assertThat(conn.isRoaming.value).isEqualTo(false)
599 assertThat(conn.isEmergencyOnly.value).isFalse()
600 assertThat(conn.isGsm.value).isFalse()
601 assertThat(conn.dataConnectionState.value).isEqualTo(DataConnectionState.Connected)
602 assertThat(conn.hasPrioritizedNetworkCapabilities.value).isFalse()
603 job.cancel()
604 }
605 }
606
607 /** Convenience to create a valid fake network event with minimal params */
validMobileEventnull608 fun validMobileEvent(
609 level: Int? = 1,
610 dataType: SignalIcon.MobileIconGroup? = THREE_G,
611 subId: Int? = 1,
612 carrierId: Int? = UNKNOWN_CARRIER_ID,
613 inflateStrength: Boolean = false,
614 activity: Int? = null,
615 carrierNetworkChange: Boolean = false,
616 roaming: Boolean = false,
617 ): FakeNetworkEventModel =
618 FakeNetworkEventModel.Mobile(
619 level = level,
620 dataType = dataType,
621 subId = subId,
622 carrierId = carrierId,
623 inflateStrength = inflateStrength,
624 activity = activity,
625 carrierNetworkChange = carrierNetworkChange,
626 roaming = roaming,
627 name = "demo name",
628 )
629
630 fun validCarrierMergedEvent(
631 subId: Int = 1,
632 level: Int = 1,
633 numberOfLevels: Int = 4,
634 activity: Int = DATA_ACTIVITY_NONE,
635 ): FakeWifiEventModel.CarrierMerged =
636 FakeWifiEventModel.CarrierMerged(
637 subscriptionId = subId,
638 level = level,
639 numberOfLevels = numberOfLevels,
640 activity = activity,
641 )
642