1 /* 2 * 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.domain.interactor 18 19 import android.telephony.CellSignalStrength 20 import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN 21 import androidx.test.filters.SmallTest 22 import com.android.settingslib.mobile.MobileIconCarrierIdOverrides 23 import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl 24 import com.android.settingslib.mobile.TelephonyIcons 25 import com.android.systemui.SysuiTestCase 26 import com.android.systemui.coroutines.collectLastValue 27 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState 28 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel 29 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.CarrierMergedNetworkType 30 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType 31 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType 32 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel 33 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository 34 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FIVE_G_OVERRIDE 35 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FOUR_G 36 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.THREE_G 37 import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel 38 import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel 39 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy 40 import com.android.systemui.util.mockito.any 41 import com.android.systemui.util.mockito.mock 42 import com.android.systemui.util.mockito.whenever 43 import com.google.common.truth.Truth.assertThat 44 import kotlinx.coroutines.ExperimentalCoroutinesApi 45 import kotlinx.coroutines.flow.MutableStateFlow 46 import kotlinx.coroutines.flow.launchIn 47 import kotlinx.coroutines.flow.onEach 48 import kotlinx.coroutines.test.TestScope 49 import kotlinx.coroutines.test.UnconfinedTestDispatcher 50 import kotlinx.coroutines.test.runTest 51 import org.junit.Before 52 import org.junit.Test 53 import org.mockito.ArgumentMatchers.anyInt 54 import org.mockito.ArgumentMatchers.anyString 55 56 @OptIn(ExperimentalCoroutinesApi::class) 57 @SmallTest 58 class MobileIconInteractorTest : SysuiTestCase() { 59 private lateinit var underTest: MobileIconInteractor 60 private val mobileMappingsProxy = FakeMobileMappingsProxy() 61 private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock()) 62 63 private val subscriptionModel = 64 MutableStateFlow( 65 SubscriptionModel( 66 subscriptionId = SUB_1_ID, 67 carrierName = DEFAULT_NAME, 68 ) 69 ) 70 71 private val connectionRepository = FakeMobileConnectionRepository(SUB_1_ID, mock()) 72 73 private val testDispatcher = UnconfinedTestDispatcher() 74 private val testScope = TestScope(testDispatcher) 75 76 @Before 77 fun setUp() { 78 underTest = createInteractor() 79 80 mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = true 81 connectionRepository.isInService.value = true 82 } 83 84 @Test 85 fun gsm_usesGsmLevel() = 86 testScope.runTest { 87 connectionRepository.isGsm.value = true 88 connectionRepository.primaryLevel.value = GSM_LEVEL 89 connectionRepository.cdmaLevel.value = CDMA_LEVEL 90 91 var latest: Int? = null 92 val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this) 93 94 assertThat(latest).isEqualTo(GSM_LEVEL) 95 96 job.cancel() 97 } 98 99 @Test 100 fun gsm_alwaysShowCdmaTrue_stillUsesGsmLevel() = 101 testScope.runTest { 102 connectionRepository.isGsm.value = true 103 connectionRepository.primaryLevel.value = GSM_LEVEL 104 connectionRepository.cdmaLevel.value = CDMA_LEVEL 105 mobileIconsInteractor.alwaysUseCdmaLevel.value = true 106 107 var latest: Int? = null 108 val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this) 109 110 assertThat(latest).isEqualTo(GSM_LEVEL) 111 112 job.cancel() 113 } 114 115 @Test 116 fun notGsm_level_default_unknown() = 117 testScope.runTest { 118 connectionRepository.isGsm.value = false 119 120 var latest: Int? = null 121 val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this) 122 123 assertThat(latest).isEqualTo(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) 124 job.cancel() 125 } 126 127 @Test 128 fun notGsm_alwaysShowCdmaTrue_usesCdmaLevel() = 129 testScope.runTest { 130 connectionRepository.isGsm.value = false 131 connectionRepository.primaryLevel.value = GSM_LEVEL 132 connectionRepository.cdmaLevel.value = CDMA_LEVEL 133 mobileIconsInteractor.alwaysUseCdmaLevel.value = true 134 135 var latest: Int? = null 136 val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this) 137 138 assertThat(latest).isEqualTo(CDMA_LEVEL) 139 140 job.cancel() 141 } 142 143 @Test 144 fun notGsm_alwaysShowCdmaFalse_usesPrimaryLevel() = 145 testScope.runTest { 146 connectionRepository.isGsm.value = false 147 connectionRepository.primaryLevel.value = GSM_LEVEL 148 connectionRepository.cdmaLevel.value = CDMA_LEVEL 149 mobileIconsInteractor.alwaysUseCdmaLevel.value = false 150 151 var latest: Int? = null 152 val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this) 153 154 assertThat(latest).isEqualTo(GSM_LEVEL) 155 156 job.cancel() 157 } 158 159 @Test 160 fun numberOfLevels_comesFromRepo() = 161 testScope.runTest { 162 var latest: Int? = null 163 val job = underTest.signalLevelIcon.onEach { latest = it.numberOfLevels }.launchIn(this) 164 165 connectionRepository.numberOfLevels.value = 5 166 assertThat(latest).isEqualTo(5) 167 168 connectionRepository.numberOfLevels.value = 4 169 assertThat(latest).isEqualTo(4) 170 171 job.cancel() 172 } 173 174 @Test 175 fun iconGroup_three_g() = 176 testScope.runTest { 177 connectionRepository.resolvedNetworkType.value = 178 DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G)) 179 180 var latest: NetworkTypeIconModel? = null 181 val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) 182 183 assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)) 184 185 job.cancel() 186 } 187 188 @Test 189 fun iconGroup_updates_on_change() = 190 testScope.runTest { 191 connectionRepository.resolvedNetworkType.value = 192 DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G)) 193 194 var latest: NetworkTypeIconModel? = null 195 val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) 196 197 connectionRepository.resolvedNetworkType.value = 198 DefaultNetworkType(mobileMappingsProxy.toIconKey(FOUR_G)) 199 200 assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.FOUR_G)) 201 202 job.cancel() 203 } 204 205 @Test 206 fun iconGroup_5g_override_type() = 207 testScope.runTest { 208 connectionRepository.resolvedNetworkType.value = 209 OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE)) 210 211 var latest: NetworkTypeIconModel? = null 212 val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) 213 214 assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.NR_5G)) 215 216 job.cancel() 217 } 218 219 @Test 220 fun iconGroup_default_if_no_lookup() = 221 testScope.runTest { 222 connectionRepository.resolvedNetworkType.value = 223 DefaultNetworkType(mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN)) 224 225 var latest: NetworkTypeIconModel? = null 226 val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) 227 228 assertThat(latest) 229 .isEqualTo(NetworkTypeIconModel.DefaultIcon(FakeMobileIconsInteractor.DEFAULT_ICON)) 230 231 job.cancel() 232 } 233 234 @Test 235 fun iconGroup_carrierMerged_usesOverride() = 236 testScope.runTest { 237 connectionRepository.resolvedNetworkType.value = CarrierMergedNetworkType 238 239 var latest: NetworkTypeIconModel? = null 240 val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) 241 242 assertThat(latest) 243 .isEqualTo( 244 NetworkTypeIconModel.DefaultIcon(CarrierMergedNetworkType.iconGroupOverride) 245 ) 246 247 job.cancel() 248 } 249 250 @Test 251 fun overrideIcon_usesCarrierIdOverride() = 252 testScope.runTest { 253 val overrides = 254 mock<MobileIconCarrierIdOverrides>().also { 255 whenever(it.carrierIdEntryExists(anyInt())).thenReturn(true) 256 whenever(it.getOverrideFor(anyInt(), anyString(), any())).thenReturn(1234) 257 } 258 259 underTest = createInteractor(overrides) 260 261 connectionRepository.resolvedNetworkType.value = 262 DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G)) 263 264 var latest: NetworkTypeIconModel? = null 265 val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) 266 267 assertThat(latest) 268 .isEqualTo(NetworkTypeIconModel.OverriddenIcon(TelephonyIcons.THREE_G, 1234)) 269 270 job.cancel() 271 } 272 273 @Test 274 fun alwaysShowDataRatIcon_matchesParent() = 275 testScope.runTest { 276 var latest: Boolean? = null 277 val job = underTest.alwaysShowDataRatIcon.onEach { latest = it }.launchIn(this) 278 279 mobileIconsInteractor.alwaysShowDataRatIcon.value = true 280 assertThat(latest).isTrue() 281 282 mobileIconsInteractor.alwaysShowDataRatIcon.value = false 283 assertThat(latest).isFalse() 284 285 job.cancel() 286 } 287 288 @Test 289 fun dataState_connected() = 290 testScope.runTest { 291 var latest: Boolean? = null 292 val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this) 293 294 connectionRepository.dataConnectionState.value = DataConnectionState.Connected 295 296 assertThat(latest).isTrue() 297 298 job.cancel() 299 } 300 301 @Test 302 fun dataState_notConnected() = 303 testScope.runTest { 304 var latest: Boolean? = null 305 val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this) 306 307 connectionRepository.dataConnectionState.value = DataConnectionState.Disconnected 308 309 assertThat(latest).isFalse() 310 311 job.cancel() 312 } 313 314 @Test 315 fun isInService_usesRepositoryValue() = 316 testScope.runTest { 317 var latest: Boolean? = null 318 val job = underTest.isInService.onEach { latest = it }.launchIn(this) 319 320 connectionRepository.isInService.value = true 321 322 assertThat(latest).isTrue() 323 324 connectionRepository.isInService.value = false 325 326 assertThat(latest).isFalse() 327 328 job.cancel() 329 } 330 331 @Test 332 fun roaming_isGsm_usesConnectionModel() = 333 testScope.runTest { 334 var latest: Boolean? = null 335 val job = underTest.isRoaming.onEach { latest = it }.launchIn(this) 336 337 connectionRepository.cdmaRoaming.value = true 338 connectionRepository.isGsm.value = true 339 connectionRepository.isRoaming.value = false 340 341 assertThat(latest).isFalse() 342 343 connectionRepository.isRoaming.value = true 344 345 assertThat(latest).isTrue() 346 347 job.cancel() 348 } 349 350 @Test 351 fun roaming_isCdma_usesCdmaRoamingBit() = 352 testScope.runTest { 353 var latest: Boolean? = null 354 val job = underTest.isRoaming.onEach { latest = it }.launchIn(this) 355 356 connectionRepository.cdmaRoaming.value = false 357 connectionRepository.isGsm.value = false 358 connectionRepository.isRoaming.value = true 359 360 assertThat(latest).isFalse() 361 362 connectionRepository.cdmaRoaming.value = true 363 connectionRepository.isGsm.value = false 364 connectionRepository.isRoaming.value = false 365 366 assertThat(latest).isTrue() 367 368 job.cancel() 369 } 370 371 @Test 372 fun roaming_falseWhileCarrierNetworkChangeActive() = 373 testScope.runTest { 374 var latest: Boolean? = null 375 val job = underTest.isRoaming.onEach { latest = it }.launchIn(this) 376 377 connectionRepository.cdmaRoaming.value = true 378 connectionRepository.isGsm.value = false 379 connectionRepository.isRoaming.value = true 380 connectionRepository.carrierNetworkChangeActive.value = true 381 382 assertThat(latest).isFalse() 383 384 connectionRepository.cdmaRoaming.value = true 385 connectionRepository.isGsm.value = true 386 387 assertThat(latest).isFalse() 388 389 job.cancel() 390 } 391 392 @Test 393 fun networkName_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() = 394 testScope.runTest { 395 var latest: NetworkNameModel? = null 396 val job = underTest.networkName.onEach { latest = it }.launchIn(this) 397 398 val testOperatorName = "operatorAlphaShort" 399 400 // Default network name, operator name is non-null, uses the operator name 401 connectionRepository.networkName.value = DEFAULT_NAME_MODEL 402 connectionRepository.operatorAlphaShort.value = testOperatorName 403 404 assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived(testOperatorName)) 405 406 // Default network name, operator name is null, uses the default 407 connectionRepository.operatorAlphaShort.value = null 408 409 assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL) 410 411 // Derived network name, operator name non-null, uses the derived name 412 connectionRepository.networkName.value = DERIVED_NAME_MODEL 413 connectionRepository.operatorAlphaShort.value = testOperatorName 414 415 assertThat(latest).isEqualTo(DERIVED_NAME_MODEL) 416 417 job.cancel() 418 } 419 420 @Test 421 fun networkNameForSubId_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() = 422 testScope.runTest { 423 var latest: String? = null 424 val job = underTest.carrierName.onEach { latest = it }.launchIn(this) 425 426 val testOperatorName = "operatorAlphaShort" 427 428 // Default network name, operator name is non-null, uses the operator name 429 connectionRepository.carrierName.value = DEFAULT_NAME_MODEL 430 connectionRepository.operatorAlphaShort.value = testOperatorName 431 432 assertThat(latest).isEqualTo(testOperatorName) 433 434 // Default network name, operator name is null, uses the default 435 connectionRepository.operatorAlphaShort.value = null 436 437 assertThat(latest).isEqualTo(DEFAULT_NAME) 438 439 // Derived network name, operator name non-null, uses the derived name 440 connectionRepository.carrierName.value = 441 NetworkNameModel.SubscriptionDerived(DERIVED_NAME) 442 connectionRepository.operatorAlphaShort.value = testOperatorName 443 444 assertThat(latest).isEqualTo(DERIVED_NAME) 445 446 job.cancel() 447 } 448 449 @Test 450 fun isSingleCarrier_matchesParent() = 451 testScope.runTest { 452 var latest: Boolean? = null 453 val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this) 454 455 mobileIconsInteractor.isSingleCarrier.value = true 456 assertThat(latest).isTrue() 457 458 mobileIconsInteractor.isSingleCarrier.value = false 459 assertThat(latest).isFalse() 460 461 job.cancel() 462 } 463 464 @Test 465 fun isForceHidden_matchesParent() = 466 testScope.runTest { 467 var latest: Boolean? = null 468 val job = underTest.isForceHidden.onEach { latest = it }.launchIn(this) 469 470 mobileIconsInteractor.isForceHidden.value = true 471 assertThat(latest).isTrue() 472 473 mobileIconsInteractor.isForceHidden.value = false 474 assertThat(latest).isFalse() 475 476 job.cancel() 477 } 478 479 @Test 480 fun isAllowedDuringAirplaneMode_matchesRepo() = 481 testScope.runTest { 482 val latest by collectLastValue(underTest.isAllowedDuringAirplaneMode) 483 484 connectionRepository.isAllowedDuringAirplaneMode.value = true 485 assertThat(latest).isTrue() 486 487 connectionRepository.isAllowedDuringAirplaneMode.value = false 488 assertThat(latest).isFalse() 489 } 490 491 @Test 492 fun iconId_correctLevel_notCutout() = 493 testScope.runTest { 494 connectionRepository.isInService.value = true 495 connectionRepository.primaryLevel.value = 1 496 connectionRepository.setDataEnabled(false) 497 498 var latest: SignalIconModel? = null 499 val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this) 500 501 assertThat(latest?.level).isEqualTo(1) 502 assertThat(latest?.showExclamationMark).isFalse() 503 504 job.cancel() 505 } 506 507 @Test 508 fun icon_usesLevelFromInteractor() = 509 testScope.runTest { 510 connectionRepository.isInService.value = true 511 512 var latest: SignalIconModel? = null 513 val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this) 514 515 connectionRepository.primaryLevel.value = 3 516 assertThat(latest!!.level).isEqualTo(3) 517 518 connectionRepository.primaryLevel.value = 1 519 assertThat(latest!!.level).isEqualTo(1) 520 521 job.cancel() 522 } 523 524 @Test 525 fun icon_usesNumberOfLevelsFromInteractor() = 526 testScope.runTest { 527 var latest: SignalIconModel? = null 528 val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this) 529 530 connectionRepository.numberOfLevels.value = 5 531 assertThat(latest!!.numberOfLevels).isEqualTo(5) 532 533 connectionRepository.numberOfLevels.value = 2 534 assertThat(latest!!.numberOfLevels).isEqualTo(2) 535 536 job.cancel() 537 } 538 539 @Test 540 fun icon_defaultDataDisabled_showExclamationTrue() = 541 testScope.runTest { 542 mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = false 543 544 var latest: SignalIconModel? = null 545 val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this) 546 547 assertThat(latest!!.showExclamationMark).isTrue() 548 549 job.cancel() 550 } 551 552 @Test 553 fun icon_defaultConnectionFailed_showExclamationTrue() = 554 testScope.runTest { 555 mobileIconsInteractor.isDefaultConnectionFailed.value = true 556 557 var latest: SignalIconModel? = null 558 val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this) 559 560 assertThat(latest!!.showExclamationMark).isTrue() 561 562 job.cancel() 563 } 564 565 @Test 566 fun icon_enabledAndNotFailed_showExclamationFalse() = 567 testScope.runTest { 568 connectionRepository.isInService.value = true 569 mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = true 570 mobileIconsInteractor.isDefaultConnectionFailed.value = false 571 572 var latest: SignalIconModel? = null 573 val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this) 574 575 assertThat(latest!!.showExclamationMark).isFalse() 576 577 job.cancel() 578 } 579 580 @Test 581 fun icon_usesEmptyState_whenNotInService() = 582 testScope.runTest { 583 var latest: SignalIconModel? = null 584 val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this) 585 586 connectionRepository.isInService.value = false 587 588 assertThat(latest?.level).isEqualTo(0) 589 assertThat(latest?.showExclamationMark).isTrue() 590 591 // Changing the level doesn't overwrite the disabled state 592 connectionRepository.primaryLevel.value = 2 593 assertThat(latest?.level).isEqualTo(0) 594 assertThat(latest?.showExclamationMark).isTrue() 595 596 // Once back in service, the regular icon appears 597 connectionRepository.isInService.value = true 598 assertThat(latest?.level).isEqualTo(2) 599 assertThat(latest?.showExclamationMark).isFalse() 600 601 job.cancel() 602 } 603 604 @Test 605 fun icon_usesCarrierNetworkState_whenInCarrierNetworkChangeMode() = 606 testScope.runTest { 607 var latest: SignalIconModel? = null 608 val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this) 609 610 connectionRepository.isInService.value = true 611 connectionRepository.carrierNetworkChangeActive.value = true 612 connectionRepository.primaryLevel.value = 1 613 connectionRepository.cdmaLevel.value = 1 614 615 assertThat(latest!!.level).isEqualTo(1) 616 assertThat(latest!!.carrierNetworkChange).isTrue() 617 618 // SignalIconModel respects the current level 619 connectionRepository.primaryLevel.value = 2 620 621 assertThat(latest!!.level).isEqualTo(2) 622 assertThat(latest!!.carrierNetworkChange).isTrue() 623 624 job.cancel() 625 } 626 627 private fun createInteractor( 628 overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl() 629 ) = 630 MobileIconInteractorImpl( 631 testScope.backgroundScope, 632 mobileIconsInteractor.activeDataConnectionHasDataEnabled, 633 mobileIconsInteractor.alwaysShowDataRatIcon, 634 mobileIconsInteractor.alwaysUseCdmaLevel, 635 mobileIconsInteractor.isSingleCarrier, 636 mobileIconsInteractor.mobileIsDefault, 637 mobileIconsInteractor.defaultMobileIconMapping, 638 mobileIconsInteractor.defaultMobileIconGroup, 639 mobileIconsInteractor.isDefaultConnectionFailed, 640 mobileIconsInteractor.isForceHidden, 641 connectionRepository, 642 context, 643 overrides, 644 ) 645 646 companion object { 647 private const val GSM_LEVEL = 1 648 private const val CDMA_LEVEL = 2 649 650 private const val SUB_1_ID = 1 651 652 private val DEFAULT_NAME = "test default name" 653 private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME) 654 private val DERIVED_NAME = "test derived name" 655 private val DERIVED_NAME_MODEL = NetworkNameModel.IntentDerived(DERIVED_NAME) 656 } 657 } 658