1 /* 2 * Copyright (C) 2024 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.media.controls.domain.pipeline 18 19 import android.app.smartspace.SmartspaceAction 20 import android.os.Bundle 21 import android.testing.TestableLooper 22 import androidx.test.ext.junit.runners.AndroidJUnit4 23 import androidx.test.filters.SmallTest 24 import com.android.internal.logging.InstanceId 25 import com.android.systemui.SysuiTestCase 26 import com.android.systemui.broadcast.BroadcastSender 27 import com.android.systemui.coroutines.collectLastValue 28 import com.android.systemui.media.controls.MediaTestUtils 29 import com.android.systemui.media.controls.data.repository.MediaFilterRepository 30 import com.android.systemui.media.controls.data.repository.mediaFilterRepository 31 import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_RESUME 32 import com.android.systemui.media.controls.shared.model.MediaCommonModel 33 import com.android.systemui.media.controls.shared.model.MediaData 34 import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel 35 import com.android.systemui.media.controls.shared.model.SmartspaceMediaData 36 import com.android.systemui.media.controls.shared.model.SmartspaceMediaLoadingModel 37 import com.android.systemui.media.controls.ui.controller.MediaPlayerData 38 import com.android.systemui.media.controls.util.MediaFlags 39 import com.android.systemui.media.controls.util.MediaUiEventLogger 40 import com.android.systemui.settings.UserTracker 41 import com.android.systemui.statusbar.NotificationLockscreenUserManager 42 import com.android.systemui.testKosmos 43 import com.android.systemui.util.time.FakeSystemClock 44 import com.google.common.truth.Truth.assertThat 45 import java.util.concurrent.Executor 46 import kotlinx.coroutines.ExperimentalCoroutinesApi 47 import kotlinx.coroutines.test.TestScope 48 import kotlinx.coroutines.test.runCurrent 49 import kotlinx.coroutines.test.runTest 50 import org.junit.Before 51 import org.junit.Test 52 import org.junit.runner.RunWith 53 import org.mockito.ArgumentMatchers.anyBoolean 54 import org.mockito.ArgumentMatchers.anyInt 55 import org.mockito.ArgumentMatchers.anyLong 56 import org.mockito.ArgumentMatchers.anyString 57 import org.mockito.Mock 58 import org.mockito.Mockito.never 59 import org.mockito.Mockito.reset 60 import org.mockito.Mockito.verify 61 import org.mockito.MockitoAnnotations 62 import org.mockito.kotlin.any 63 import org.mockito.kotlin.eq 64 import org.mockito.kotlin.whenever 65 66 private const val KEY = "TEST_KEY" 67 private const val KEY_ALT = "TEST_KEY_2" 68 private const val USER_MAIN = 0 69 private const val USER_GUEST = 10 70 private const val PRIVATE_PROFILE = 12 71 private const val PACKAGE = "PKG" 72 private val INSTANCE_ID = InstanceId.fakeInstanceId(123)!! 73 private val INSTANCE_ID_GUEST = InstanceId.fakeInstanceId(321)!! 74 private const val APP_UID = 99 75 private const val SMARTSPACE_KEY = "SMARTSPACE_KEY" 76 private const val SMARTSPACE_PACKAGE = "SMARTSPACE_PKG" 77 private val SMARTSPACE_INSTANCE_ID = InstanceId.fakeInstanceId(456)!! 78 79 @ExperimentalCoroutinesApi 80 @SmallTest 81 @RunWith(AndroidJUnit4::class) 82 @TestableLooper.RunWithLooper 83 class MediaDataFilterImplTest : SysuiTestCase() { 84 val kosmos = testKosmos() 85 86 @Mock private lateinit var listener: MediaDataProcessor.Listener 87 @Mock private lateinit var userTracker: UserTracker 88 @Mock private lateinit var broadcastSender: BroadcastSender 89 @Mock private lateinit var mediaDataProcessor: MediaDataProcessor 90 @Mock private lateinit var lockscreenUserManager: NotificationLockscreenUserManager 91 @Mock private lateinit var executor: Executor 92 @Mock private lateinit var smartspaceData: SmartspaceMediaData 93 @Mock private lateinit var smartspaceMediaRecommendationItem: SmartspaceAction 94 @Mock private lateinit var logger: MediaUiEventLogger 95 @Mock private lateinit var mediaFlags: MediaFlags 96 @Mock private lateinit var cardAction: SmartspaceAction 97 98 private lateinit var mediaDataFilter: MediaDataFilterImpl 99 private lateinit var testScope: TestScope 100 private lateinit var dataMain: MediaData 101 private lateinit var dataGuest: MediaData 102 private lateinit var dataPrivateProfile: MediaData 103 private val clock = FakeSystemClock() 104 private val repository: MediaFilterRepository = kosmos.mediaFilterRepository 105 private val mediaLoadingLogger = kosmos.mockMediaLoadingLogger 106 107 @Before setupnull108 fun setup() { 109 MockitoAnnotations.initMocks(this) 110 MediaPlayerData.clear() 111 whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false) 112 testScope = TestScope() 113 mediaDataFilter = 114 MediaDataFilterImpl( 115 context, 116 userTracker, 117 broadcastSender, 118 lockscreenUserManager, 119 executor, 120 clock, 121 logger, 122 mediaFlags, 123 repository, 124 mediaLoadingLogger, 125 ) 126 mediaDataFilter.mediaDataProcessor = mediaDataProcessor 127 mediaDataFilter.addListener(listener) 128 129 // Start all tests as main user 130 setUser(USER_MAIN) 131 132 // Set up test media data 133 dataMain = 134 MediaTestUtils.emptyMediaData.copy( 135 userId = USER_MAIN, 136 packageName = PACKAGE, 137 instanceId = INSTANCE_ID, 138 appUid = APP_UID 139 ) 140 dataGuest = dataMain.copy(userId = USER_GUEST, instanceId = INSTANCE_ID_GUEST) 141 dataPrivateProfile = dataMain.copy(userId = PRIVATE_PROFILE, instanceId = INSTANCE_ID_GUEST) 142 143 whenever(smartspaceData.targetId).thenReturn(SMARTSPACE_KEY) 144 whenever(smartspaceData.isActive).thenReturn(true) 145 whenever(smartspaceData.isValid()).thenReturn(true) 146 whenever(smartspaceData.packageName).thenReturn(SMARTSPACE_PACKAGE) 147 whenever(smartspaceData.recommendations) 148 .thenReturn(listOf(smartspaceMediaRecommendationItem)) 149 whenever(smartspaceData.headphoneConnectionTimeMillis) 150 .thenReturn(clock.currentTimeMillis() - 100) 151 whenever(smartspaceData.instanceId).thenReturn(SMARTSPACE_INSTANCE_ID) 152 whenever(smartspaceData.cardAction).thenReturn(cardAction) 153 } 154 setUsernull155 private fun setUser(id: Int) { 156 whenever(lockscreenUserManager.isCurrentProfile(anyInt())).thenReturn(false) 157 whenever(lockscreenUserManager.isProfileAvailable(anyInt())).thenReturn(false) 158 whenever(lockscreenUserManager.isCurrentProfile(eq(id))).thenReturn(true) 159 whenever(lockscreenUserManager.isProfileAvailable(eq(id))).thenReturn(true) 160 whenever(lockscreenUserManager.isProfileAvailable(eq(PRIVATE_PROFILE))).thenReturn(true) 161 mediaDataFilter.handleUserSwitched() 162 } 163 setPrivateProfileUnavailablenull164 private fun setPrivateProfileUnavailable() { 165 whenever(lockscreenUserManager.isCurrentProfile(anyInt())).thenReturn(false) 166 whenever(lockscreenUserManager.isCurrentProfile(eq(USER_MAIN))).thenReturn(true) 167 whenever(lockscreenUserManager.isCurrentProfile(eq(PRIVATE_PROFILE))).thenReturn(true) 168 whenever(lockscreenUserManager.isProfileAvailable(eq(PRIVATE_PROFILE))).thenReturn(false) 169 mediaDataFilter.handleProfileChanged() 170 } 171 172 @Test onDataLoadedForCurrentUser_updatesLoadedStatesnull173 fun onDataLoadedForCurrentUser_updatesLoadedStates() = 174 testScope.runTest { 175 val currentMedia by collectLastValue(repository.currentMedia) 176 val mediaCommonModel = 177 MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(dataMain.instanceId)) 178 179 mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) 180 181 verify(listener) 182 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataMain), eq(true), eq(0), eq(false)) 183 verify(mediaLoadingLogger) 184 .logMediaLoaded(eq(dataMain.instanceId), eq(dataMain.active), anyString()) 185 assertThat(currentMedia).containsExactly(mediaCommonModel) 186 } 187 188 @Test onDataLoadedForGuest_doesNotUpdateLoadedStatesnull189 fun onDataLoadedForGuest_doesNotUpdateLoadedStates() = 190 testScope.runTest { 191 val currentMedia by collectLastValue(repository.currentMedia) 192 val mediaCommonModel = 193 MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(dataMain.instanceId)) 194 195 mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest) 196 197 verify(listener, never()) 198 .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean()) 199 verify(mediaLoadingLogger, never()).logMediaLoaded(any(), anyBoolean(), anyString()) 200 assertThat(currentMedia).doesNotContain(mediaCommonModel) 201 } 202 203 @Test onRemovedForCurrent_updatesLoadedStatesnull204 fun onRemovedForCurrent_updatesLoadedStates() = 205 testScope.runTest { 206 val currentMedia by collectLastValue(repository.currentMedia) 207 val mediaCommonModel = 208 MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(dataMain.instanceId)) 209 210 // GIVEN a media was removed for main user 211 mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) 212 213 verify(mediaLoadingLogger) 214 .logMediaLoaded(eq(dataMain.instanceId), eq(dataMain.active), anyString()) 215 assertThat(currentMedia).containsExactly(mediaCommonModel) 216 217 mediaDataFilter.onMediaDataRemoved(KEY, false) 218 219 verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) 220 verify(mediaLoadingLogger).logMediaRemoved(eq(dataMain.instanceId), anyString()) 221 assertThat(currentMedia).doesNotContain(mediaCommonModel) 222 } 223 224 @Test onRemovedForGuest_doesNotUpdateLoadedStatesnull225 fun onRemovedForGuest_doesNotUpdateLoadedStates() = 226 testScope.runTest { 227 val currentMedia by collectLastValue(repository.currentMedia) 228 229 // GIVEN a media was removed for guest user 230 mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest) 231 mediaDataFilter.onMediaDataRemoved(KEY, false) 232 233 verify(listener, never()).onMediaDataRemoved(eq(KEY), eq(false)) 234 verify(mediaLoadingLogger, never()) 235 .logMediaRemoved(eq(dataGuest.instanceId), anyString()) 236 assertThat(currentMedia).isEmpty() 237 } 238 239 @Test onUserSwitched_removesOldUserControlsnull240 fun onUserSwitched_removesOldUserControls() = 241 testScope.runTest { 242 val currentMedia by collectLastValue(repository.currentMedia) 243 val mediaLoaded = MediaDataLoadingModel.Loaded(dataMain.instanceId) 244 245 // GIVEN that we have a media loaded for main user 246 mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) 247 248 verify(mediaLoadingLogger) 249 .logMediaLoaded(eq(dataMain.instanceId), eq(dataMain.active), anyString()) 250 assertThat(currentMedia).containsExactly(MediaCommonModel.MediaControl(mediaLoaded)) 251 252 // and we switch to guest user 253 setUser(USER_GUEST) 254 255 // THEN we should remove the main user's media 256 verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) 257 verify(mediaLoadingLogger).logMediaRemoved(eq(dataMain.instanceId), anyString()) 258 assertThat(currentMedia).isEmpty() 259 } 260 261 @Test onUserSwitched_addsNewUserControlsnull262 fun onUserSwitched_addsNewUserControls() = 263 testScope.runTest { 264 val currentMedia by collectLastValue(repository.currentMedia) 265 val guestLoadedStatesModel = MediaDataLoadingModel.Loaded(dataGuest.instanceId) 266 val mainLoadedStatesModel = MediaDataLoadingModel.Loaded(dataMain.instanceId) 267 268 // GIVEN that we had some media for both users 269 mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) 270 mediaDataFilter.onMediaDataLoaded(KEY_ALT, null, dataGuest) 271 272 // and we switch to guest user 273 setUser(USER_GUEST) 274 275 // THEN we should add back the guest user media 276 verify(listener) 277 .onMediaDataLoaded(eq(KEY_ALT), eq(null), eq(dataGuest), eq(true), eq(0), eq(false)) 278 verify(mediaLoadingLogger) 279 .logMediaLoaded(eq(dataGuest.instanceId), eq(dataGuest.active), anyString()) 280 281 reset(mediaLoadingLogger) 282 283 // but not the main user's 284 verify(listener, never()) 285 .onMediaDataLoaded( 286 eq(KEY), 287 any(), 288 eq(dataMain), 289 anyBoolean(), 290 anyInt(), 291 anyBoolean() 292 ) 293 verify(mediaLoadingLogger, never()) 294 .logMediaLoaded(eq(dataMain.instanceId), anyBoolean(), anyString()) 295 assertThat(currentMedia) 296 .containsExactly(MediaCommonModel.MediaControl(guestLoadedStatesModel)) 297 assertThat(currentMedia) 298 .doesNotContain(MediaCommonModel.MediaControl(mainLoadedStatesModel)) 299 } 300 301 @Test onProfileChanged_profileUnavailable_updateStatesnull302 fun onProfileChanged_profileUnavailable_updateStates() = 303 testScope.runTest { 304 val currentMedia by collectLastValue(repository.currentMedia) 305 306 // GIVEN that we had some media for both profiles 307 mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) 308 mediaDataFilter.onMediaDataLoaded(KEY_ALT, null, dataPrivateProfile) 309 310 // and we change profile status 311 setPrivateProfileUnavailable() 312 313 val mediaLoadedStatesModel = MediaDataLoadingModel.Loaded(dataMain.instanceId) 314 // THEN we should remove the private profile media 315 verify(listener).onMediaDataRemoved(eq(KEY_ALT), eq(false)) 316 verify(mediaLoadingLogger).logMediaRemoved(eq(dataGuest.instanceId), anyString()) 317 assertThat(currentMedia) 318 .containsExactly(MediaCommonModel.MediaControl(mediaLoadedStatesModel)) 319 } 320 321 @Test hasAnyMedia_mediaSet_returnsTruenull322 fun hasAnyMedia_mediaSet_returnsTrue() = 323 testScope.runTest { 324 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 325 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain) 326 327 assertThat(hasAnyMedia(selectedUserEntries)).isTrue() 328 } 329 330 @Test hasAnyMedia_recommendationSet_returnsFalsenull331 fun hasAnyMedia_recommendationSet_returnsFalse() = 332 testScope.runTest { 333 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 334 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 335 336 assertThat(hasAnyMedia(selectedUserEntries)).isFalse() 337 } 338 339 @Test hasAnyMediaOrRecommendation_mediaSet_returnsTruenull340 fun hasAnyMediaOrRecommendation_mediaSet_returnsTrue() = 341 testScope.runTest { 342 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 343 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 344 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain) 345 346 assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData)) 347 .isTrue() 348 } 349 350 @Test hasAnyMediaOrRecommendation_recommendationSet_returnsTruenull351 fun hasAnyMediaOrRecommendation_recommendationSet_returnsTrue() = 352 testScope.runTest { 353 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 354 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 355 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 356 357 assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData)) 358 .isTrue() 359 } 360 361 @Test hasActiveMedia_inactiveMediaSet_returnsFalsenull362 fun hasActiveMedia_inactiveMediaSet_returnsFalse() = 363 testScope.runTest { 364 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 365 366 val data = dataMain.copy(active = false) 367 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) 368 369 assertThat(hasActiveMedia(selectedUserEntries)).isFalse() 370 } 371 372 @Test hasActiveMedia_activeMediaSet_returnsTruenull373 fun hasActiveMedia_activeMediaSet_returnsTrue() = 374 testScope.runTest { 375 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 376 val data = dataMain.copy(active = true) 377 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) 378 379 assertThat(hasActiveMedia(selectedUserEntries)).isTrue() 380 } 381 382 @Test hasActiveMediaOrRecommendation_inactiveMediaSet_returnsFalsenull383 fun hasActiveMediaOrRecommendation_inactiveMediaSet_returnsFalse() = 384 testScope.runTest { 385 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 386 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 387 val reactivatedKey by collectLastValue(repository.reactivatedId) 388 val data = dataMain.copy(active = false) 389 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) 390 391 assertThat( 392 hasActiveMediaOrRecommendation( 393 selectedUserEntries, 394 smartspaceMediaData, 395 reactivatedKey 396 ) 397 ) 398 .isFalse() 399 } 400 401 @Test hasActiveMediaOrRecommendation_activeMediaSet_returnsTruenull402 fun hasActiveMediaOrRecommendation_activeMediaSet_returnsTrue() = 403 testScope.runTest { 404 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 405 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 406 val reactivatedKey by collectLastValue(repository.reactivatedId) 407 val data = dataMain.copy(active = true) 408 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) 409 410 assertThat( 411 hasActiveMediaOrRecommendation( 412 selectedUserEntries, 413 smartspaceMediaData, 414 reactivatedKey 415 ) 416 ) 417 .isTrue() 418 } 419 420 @Test hasActiveMediaOrRecommendation_inactiveRecommendationSet_returnsFalsenull421 fun hasActiveMediaOrRecommendation_inactiveRecommendationSet_returnsFalse() = 422 testScope.runTest { 423 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 424 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 425 val reactivatedKey by collectLastValue(repository.reactivatedId) 426 whenever(smartspaceData.isActive).thenReturn(false) 427 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 428 429 assertThat( 430 hasActiveMediaOrRecommendation( 431 selectedUserEntries, 432 smartspaceMediaData, 433 reactivatedKey 434 ) 435 ) 436 .isFalse() 437 } 438 439 @Test hasActiveMediaOrRecommendation_invalidRecommendationSet_returnsFalsenull440 fun hasActiveMediaOrRecommendation_invalidRecommendationSet_returnsFalse() = 441 testScope.runTest { 442 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 443 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 444 val reactivatedKey by collectLastValue(repository.reactivatedId) 445 whenever(smartspaceData.isValid()).thenReturn(false) 446 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 447 448 assertThat( 449 hasActiveMediaOrRecommendation( 450 selectedUserEntries, 451 smartspaceMediaData, 452 reactivatedKey 453 ) 454 ) 455 .isFalse() 456 } 457 458 @Test hasActiveMediaOrRecommendation_activeAndValidRecommendationSet_returnsTruenull459 fun hasActiveMediaOrRecommendation_activeAndValidRecommendationSet_returnsTrue() = 460 testScope.runTest { 461 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 462 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 463 val reactivatedKey by collectLastValue(repository.reactivatedId) 464 whenever(smartspaceData.isActive).thenReturn(true) 465 whenever(smartspaceData.isValid()).thenReturn(true) 466 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 467 468 assertThat( 469 hasActiveMediaOrRecommendation( 470 selectedUserEntries, 471 smartspaceMediaData, 472 reactivatedKey 473 ) 474 ) 475 .isTrue() 476 } 477 478 @Test hasAnyMediaOrRecommendation_onlyCurrentUsernull479 fun hasAnyMediaOrRecommendation_onlyCurrentUser() = 480 testScope.runTest { 481 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 482 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 483 assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData)) 484 .isFalse() 485 486 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataGuest) 487 assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData)) 488 .isFalse() 489 assertThat(hasAnyMedia(selectedUserEntries)).isFalse() 490 } 491 492 @Test hasActiveMediaOrRecommendation_onlyCurrentUsernull493 fun hasActiveMediaOrRecommendation_onlyCurrentUser() = 494 testScope.runTest { 495 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 496 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 497 val reactivatedKey by collectLastValue(repository.reactivatedId) 498 assertThat( 499 hasActiveMediaOrRecommendation( 500 selectedUserEntries, 501 smartspaceMediaData, 502 reactivatedKey 503 ) 504 ) 505 .isFalse() 506 val data = dataGuest.copy(active = true) 507 508 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) 509 assertThat( 510 hasActiveMediaOrRecommendation( 511 selectedUserEntries, 512 smartspaceMediaData, 513 reactivatedKey 514 ) 515 ) 516 .isFalse() 517 assertThat(hasAnyMedia(selectedUserEntries)).isFalse() 518 } 519 520 @Test onNotificationRemoved_doesNotHaveMedianull521 fun onNotificationRemoved_doesNotHaveMedia() = 522 testScope.runTest { 523 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 524 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 525 526 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain) 527 mediaDataFilter.onMediaDataRemoved(KEY, false) 528 assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData)) 529 .isFalse() 530 assertThat(hasAnyMedia(selectedUserEntries)).isFalse() 531 } 532 533 @Test onSwipeToDismiss_setsTimedOutnull534 fun onSwipeToDismiss_setsTimedOut() { 535 mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) 536 mediaDataFilter.onSwipeToDismiss() 537 538 verify(mediaDataProcessor).setInactive(eq(KEY), eq(true), eq(true)) 539 } 540 541 @Test onSmartspaceMediaDataLoaded_noMedia_activeValidRec_prioritizesSmartspacenull542 fun onSmartspaceMediaDataLoaded_noMedia_activeValidRec_prioritizesSmartspace() = 543 testScope.runTest { 544 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 545 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 546 val reactivatedKey by collectLastValue(repository.reactivatedId) 547 val currentMedia by collectLastValue(repository.currentMedia) 548 val recommendationsLoadingModel = 549 SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY, isPrioritized = true) 550 551 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 552 553 assertThat(currentMedia) 554 .containsExactly(MediaCommonModel.MediaRecommendations(recommendationsLoadingModel)) 555 assertThat( 556 hasActiveMediaOrRecommendation( 557 selectedUserEntries, 558 smartspaceMediaData, 559 reactivatedKey 560 ) 561 ) 562 .isTrue() 563 assertThat(hasActiveMedia(selectedUserEntries)).isFalse() 564 verify(listener) 565 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true)) 566 verify(mediaLoadingLogger) 567 .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString()) 568 verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID) 569 verify(logger, never()).logRecommendationActivated(any(), any(), any()) 570 } 571 572 @Test onSmartspaceMediaDataLoaded_noMedia_inactiveRec_showsNothingnull573 fun onSmartspaceMediaDataLoaded_noMedia_inactiveRec_showsNothing() = 574 testScope.runTest { 575 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 576 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 577 val reactivatedKey by collectLastValue(repository.reactivatedId) 578 val currentMedia by collectLastValue(repository.currentMedia) 579 580 whenever(smartspaceData.isActive).thenReturn(false) 581 582 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 583 584 assertThat(currentMedia).isEmpty() 585 assertThat( 586 hasActiveMediaOrRecommendation( 587 selectedUserEntries, 588 smartspaceMediaData, 589 reactivatedKey 590 ) 591 ) 592 .isFalse() 593 assertThat(hasActiveMedia(selectedUserEntries)).isFalse() 594 verify(listener, never()) 595 .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean()) 596 verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean()) 597 verify(mediaLoadingLogger, never()).logMediaLoaded(any(), anyBoolean(), anyString()) 598 verify(mediaLoadingLogger, never()) 599 .logRecommendationLoaded(any(), anyBoolean(), anyString()) 600 verify(logger, never()).logRecommendationAdded(any(), any()) 601 verify(logger, never()).logRecommendationActivated(any(), any(), any()) 602 } 603 604 @Test onSmartspaceMediaDataLoaded_noRecentMedia_activeValidRec_prioritizesSmartspacenull605 fun onSmartspaceMediaDataLoaded_noRecentMedia_activeValidRec_prioritizesSmartspace() = 606 testScope.runTest { 607 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 608 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 609 val reactivatedKey by collectLastValue(repository.reactivatedId) 610 val currentMedia by collectLastValue(repository.currentMedia) 611 val recsCommonModel = 612 MediaCommonModel.MediaRecommendations( 613 SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY, isPrioritized = true) 614 ) 615 val controlCommonModel = 616 MediaCommonModel.MediaControl( 617 MediaDataLoadingModel.Loaded(dataMain.instanceId), 618 true 619 ) 620 val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 621 mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld) 622 clock.advanceTime(MediaDataFilterImpl.SMARTSPACE_MAX_AGE + 100) 623 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 624 625 assertThat(currentMedia).containsExactly(recsCommonModel, controlCommonModel) 626 assertThat( 627 hasActiveMediaOrRecommendation( 628 selectedUserEntries, 629 smartspaceMediaData, 630 reactivatedKey 631 ) 632 ) 633 .isTrue() 634 assertThat(hasActiveMedia(selectedUserEntries)).isFalse() 635 verify(listener) 636 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true)) 637 verify(mediaLoadingLogger) 638 .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString()) 639 verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID) 640 verify(logger, never()).logRecommendationActivated(any(), any(), any()) 641 } 642 643 @Test onSmartspaceMediaDataLoaded_noRecentMedia_inactiveRec_showsNothingnull644 fun onSmartspaceMediaDataLoaded_noRecentMedia_inactiveRec_showsNothing() = 645 testScope.runTest { 646 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 647 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 648 val reactivatedKey by collectLastValue(repository.reactivatedId) 649 val currentMedia by collectLastValue(repository.currentMedia) 650 whenever(smartspaceData.isActive).thenReturn(false) 651 652 val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 653 mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld) 654 clock.advanceTime(MediaDataFilterImpl.SMARTSPACE_MAX_AGE + 100) 655 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 656 657 assertThat(currentMedia) 658 .doesNotContain( 659 MediaCommonModel.MediaRecommendations( 660 SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) 661 ) 662 ) 663 assertThat( 664 hasActiveMediaOrRecommendation( 665 selectedUserEntries, 666 smartspaceMediaData, 667 reactivatedKey 668 ) 669 ) 670 .isFalse() 671 assertThat(hasActiveMedia(selectedUserEntries)).isFalse() 672 verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean()) 673 verify(mediaLoadingLogger, never()) 674 .logRecommendationLoaded(any(), anyBoolean(), anyString()) 675 verify(logger, never()).logRecommendationAdded(any(), any()) 676 verify(logger, never()).logRecommendationActivated(any(), any(), any()) 677 } 678 679 @Test onSmartspaceMediaDataLoaded_hasRecentMedia_inactiveRec_showsNothingnull680 fun onSmartspaceMediaDataLoaded_hasRecentMedia_inactiveRec_showsNothing() = 681 testScope.runTest { 682 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 683 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 684 val reactivatedKey by collectLastValue(repository.reactivatedId) 685 val currentMedia by collectLastValue(repository.currentMedia) 686 687 whenever(smartspaceData.isActive).thenReturn(false) 688 689 // WHEN we have media that was recently played, but not currently active 690 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 691 val controlCommonModel = 692 MediaCommonModel.MediaControl( 693 MediaDataLoadingModel.Loaded(dataMain.instanceId), 694 true 695 ) 696 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 697 repository.setOrderedMedia() 698 699 assertThat(currentMedia).containsExactly(controlCommonModel) 700 verify(listener) 701 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 702 verify(mediaLoadingLogger) 703 .logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString()) 704 705 reset(mediaLoadingLogger) 706 707 // AND we get a smartspace signal 708 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 709 710 // THEN we should treat the media as not active instead 711 assertThat(currentMedia).containsExactly(controlCommonModel) 712 assertThat( 713 hasActiveMediaOrRecommendation( 714 selectedUserEntries, 715 smartspaceMediaData, 716 reactivatedKey 717 ) 718 ) 719 .isFalse() 720 assertThat(hasActiveMedia(selectedUserEntries)).isFalse() 721 verify(listener, never()) 722 .onMediaDataLoaded(eq(KEY), eq(KEY), any(), anyBoolean(), anyInt(), anyBoolean()) 723 verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean()) 724 verify(mediaLoadingLogger, never()) 725 .logMediaLoaded(eq(dataCurrent.instanceId), anyBoolean(), anyString()) 726 verify(mediaLoadingLogger, never()) 727 .logRecommendationLoaded(any(), anyBoolean(), anyString()) 728 verify(logger, never()).logRecommendationAdded(any(), any()) 729 verify(logger, never()).logRecommendationActivated(any(), any(), any()) 730 } 731 732 @Test onSmartspaceMediaDataLoaded_hasRecentMedia_activeInvalidRec_usesMedianull733 fun onSmartspaceMediaDataLoaded_hasRecentMedia_activeInvalidRec_usesMedia() = 734 testScope.runTest { 735 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 736 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 737 val reactivatedKey by collectLastValue(repository.reactivatedId) 738 val currentMedia by collectLastValue(repository.currentMedia) 739 whenever(smartspaceData.isValid()).thenReturn(false) 740 741 // WHEN we have media that was recently played, but not currently active 742 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 743 val controlCommonModel = 744 MediaCommonModel.MediaControl( 745 MediaDataLoadingModel.Loaded(dataMain.instanceId), 746 true 747 ) 748 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 749 repository.setOrderedMedia() 750 assertThat(currentMedia).containsExactly(controlCommonModel) 751 verify(listener) 752 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 753 verify(mediaLoadingLogger) 754 .logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString()) 755 756 // AND we get a smartspace signal 757 runCurrent() 758 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 759 760 // THEN we should treat the media as active instead 761 val dataCurrentAndActive = dataCurrent.copy(active = true) 762 assertThat(currentMedia).containsExactly(controlCommonModel) 763 assertThat( 764 hasActiveMediaOrRecommendation( 765 selectedUserEntries, 766 smartspaceMediaData, 767 reactivatedKey 768 ) 769 ) 770 .isTrue() 771 verify(listener) 772 .onMediaDataLoaded( 773 eq(KEY), 774 eq(KEY), 775 eq(dataCurrentAndActive), 776 eq(true), 777 eq(100), 778 eq(true) 779 ) 780 verify(mediaLoadingLogger) 781 .logMediaLoaded( 782 eq(dataCurrentAndActive.instanceId), 783 eq(dataCurrentAndActive.active), 784 anyString() 785 ) 786 // Smartspace update shouldn't be propagated for the empty rec list. 787 verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean()) 788 verify(mediaLoadingLogger, never()) 789 .logRecommendationLoaded(any(), anyBoolean(), anyString()) 790 verify(logger, never()).logRecommendationAdded(any(), any()) 791 verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID)) 792 } 793 794 @Test onSmartspaceMediaDataLoaded_hasRecentMedia_activeValidRec_usesBothnull795 fun onSmartspaceMediaDataLoaded_hasRecentMedia_activeValidRec_usesBoth() = 796 testScope.runTest { 797 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 798 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 799 val reactivatedKey by collectLastValue(repository.reactivatedId) 800 val currentMedia by collectLastValue(repository.currentMedia) 801 // WHEN we have media that was recently played, but not currently active 802 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 803 val controlCommonModel = 804 MediaCommonModel.MediaControl( 805 MediaDataLoadingModel.Loaded(dataMain.instanceId), 806 true 807 ) 808 val recsCommonModel = 809 MediaCommonModel.MediaRecommendations( 810 SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) 811 ) 812 813 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 814 repository.setOrderedMedia() 815 816 assertThat(currentMedia).containsExactly(controlCommonModel) 817 verify(listener) 818 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 819 verify(mediaLoadingLogger) 820 .logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString()) 821 822 // AND we get a smartspace signal 823 runCurrent() 824 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 825 826 // THEN we should treat the media as active instead 827 val dataCurrentAndActive = dataCurrent.copy(active = true) 828 verify(listener) 829 .onMediaDataLoaded( 830 eq(KEY), 831 eq(KEY), 832 eq(dataCurrentAndActive), 833 eq(true), 834 eq(100), 835 eq(true) 836 ) 837 verify(mediaLoadingLogger) 838 .logMediaLoaded( 839 eq(dataCurrentAndActive.instanceId), 840 eq(dataCurrentAndActive.active), 841 anyString() 842 ) 843 assertThat( 844 hasActiveMediaOrRecommendation( 845 selectedUserEntries, 846 smartspaceMediaData, 847 reactivatedKey 848 ) 849 ) 850 .isTrue() 851 // Smartspace update should also be propagated but not prioritized. 852 assertThat(currentMedia).containsExactly(controlCommonModel, recsCommonModel) 853 verify(listener) 854 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) 855 verify(mediaLoadingLogger) 856 .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString()) 857 verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID) 858 verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID)) 859 } 860 861 @Test onSmartspaceMediaDataRemoved_usedSmartspace_clearsSmartspacenull862 fun onSmartspaceMediaDataRemoved_usedSmartspace_clearsSmartspace() = 863 testScope.runTest { 864 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 865 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 866 val reactivatedKey by collectLastValue(repository.reactivatedId) 867 val currentMedia by collectLastValue(repository.currentMedia) 868 869 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 870 mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) 871 872 verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) 873 verify(mediaLoadingLogger) 874 .logRecommendationRemoved(eq(SMARTSPACE_KEY), eq(true), anyString()) 875 assertThat(currentMedia).isEmpty() 876 assertThat( 877 hasActiveMediaOrRecommendation( 878 selectedUserEntries, 879 smartspaceMediaData, 880 reactivatedKey 881 ) 882 ) 883 .isFalse() 884 assertThat(hasActiveMedia(selectedUserEntries)).isFalse() 885 } 886 887 @Test onSmartspaceMediaDataRemoved_usedMediaAndSmartspace_clearsBothnull888 fun onSmartspaceMediaDataRemoved_usedMediaAndSmartspace_clearsBoth() = 889 testScope.runTest { 890 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 891 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 892 val reactivatedKey by collectLastValue(repository.reactivatedId) 893 val currentMedia by collectLastValue(repository.currentMedia) 894 val controlCommonModel = 895 MediaCommonModel.MediaControl( 896 MediaDataLoadingModel.Loaded(dataMain.instanceId), 897 true 898 ) 899 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 900 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 901 repository.setOrderedMedia() 902 903 assertThat(currentMedia).containsExactly(controlCommonModel) 904 verify(listener) 905 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 906 verify(mediaLoadingLogger) 907 .logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString()) 908 909 runCurrent() 910 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 911 912 val dataCurrentAndActive = dataCurrent.copy(active = true) 913 verify(listener) 914 .onMediaDataLoaded( 915 eq(KEY), 916 eq(KEY), 917 eq(dataCurrentAndActive), 918 eq(true), 919 eq(100), 920 eq(true) 921 ) 922 verify(mediaLoadingLogger) 923 .logMediaLoaded( 924 eq(dataCurrentAndActive.instanceId), 925 eq(dataCurrentAndActive.active), 926 anyString() 927 ) 928 929 mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) 930 931 verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) 932 verify(mediaLoadingLogger) 933 .logRecommendationRemoved(eq(SMARTSPACE_KEY), eq(true), anyString()) 934 assertThat(currentMedia).containsExactly(controlCommonModel) 935 assertThat( 936 hasActiveMediaOrRecommendation( 937 selectedUserEntries, 938 smartspaceMediaData, 939 reactivatedKey 940 ) 941 ) 942 .isFalse() 943 assertThat(hasActiveMedia(selectedUserEntries)).isFalse() 944 } 945 946 @Test onSmartspaceLoaded_persistentEnabled_isInactivenull947 fun onSmartspaceLoaded_persistentEnabled_isInactive() = 948 testScope.runTest { 949 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 950 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 951 val reactivatedKey by collectLastValue(repository.reactivatedId) 952 val currentMedia by collectLastValue(repository.currentMedia) 953 val recsCommonModel = 954 MediaCommonModel.MediaRecommendations( 955 SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) 956 ) 957 whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(true) 958 whenever(smartspaceData.isActive).thenReturn(false) 959 960 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 961 962 verify(listener) 963 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) 964 verify(mediaLoadingLogger) 965 .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(false), anyString()) 966 assertThat(currentMedia).containsExactly(recsCommonModel) 967 assertThat( 968 hasActiveMediaOrRecommendation( 969 selectedUserEntries, 970 smartspaceMediaData, 971 reactivatedKey 972 ) 973 ) 974 .isFalse() 975 assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData)) 976 .isTrue() 977 } 978 979 @Test onSmartspaceLoaded_persistentEnabled_inactive_hasRecentMedia_staysInactivenull980 fun onSmartspaceLoaded_persistentEnabled_inactive_hasRecentMedia_staysInactive() = 981 testScope.runTest { 982 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 983 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 984 val reactivatedKey by collectLastValue(repository.reactivatedId) 985 val currentMedia by collectLastValue(repository.currentMedia) 986 val recsCommonModel = 987 MediaCommonModel.MediaRecommendations( 988 SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) 989 ) 990 val controlCommonModel = 991 MediaCommonModel.MediaControl( 992 MediaDataLoadingModel.Loaded(dataMain.instanceId), 993 true 994 ) 995 996 whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(true) 997 whenever(smartspaceData.isActive).thenReturn(false) 998 999 // If there is media that was recently played but inactive 1000 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 1001 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 1002 repository.setOrderedMedia() 1003 1004 verify(listener) 1005 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 1006 verify(mediaLoadingLogger) 1007 .logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString()) 1008 assertThat(currentMedia).containsExactly(controlCommonModel) 1009 1010 reset(mediaLoadingLogger) 1011 1012 // And an inactive recommendation is loaded 1013 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 1014 1015 // Smartspace is loaded but the media stays inactive 1016 verify(listener) 1017 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) 1018 verify(mediaLoadingLogger) 1019 .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(false), anyString()) 1020 verify(listener, never()) 1021 .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean()) 1022 verify(mediaLoadingLogger, never()).logMediaLoaded(any(), anyBoolean(), anyString()) 1023 assertThat(currentMedia).containsExactly(controlCommonModel, recsCommonModel) 1024 assertThat( 1025 hasActiveMediaOrRecommendation( 1026 selectedUserEntries, 1027 smartspaceMediaData, 1028 reactivatedKey 1029 ) 1030 ) 1031 .isFalse() 1032 assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData)) 1033 .isTrue() 1034 } 1035 1036 @Test onSwipeToDismiss_persistentEnabled_recommendationSetInactivenull1037 fun onSwipeToDismiss_persistentEnabled_recommendationSetInactive() { 1038 whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(true) 1039 1040 val data = 1041 EMPTY_SMARTSPACE_MEDIA_DATA.copy( 1042 targetId = SMARTSPACE_KEY, 1043 isActive = true, 1044 packageName = SMARTSPACE_PACKAGE, 1045 recommendations = listOf(smartspaceMediaRecommendationItem), 1046 ) 1047 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, data) 1048 mediaDataFilter.onSwipeToDismiss() 1049 1050 verify(mediaDataProcessor).setRecommendationInactive(eq(SMARTSPACE_KEY)) 1051 verify(mediaDataProcessor, never()) 1052 .dismissSmartspaceRecommendation(eq(SMARTSPACE_KEY), anyLong()) 1053 } 1054 1055 @Test smartspaceLoaded_shouldTriggerResume_doesTriggernull1056 fun smartspaceLoaded_shouldTriggerResume_doesTrigger() = 1057 testScope.runTest { 1058 val selectedUserEntries by collectLastValue(repository.selectedUserEntries) 1059 val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) 1060 val reactivatedKey by collectLastValue(repository.reactivatedId) 1061 val currentMedia by collectLastValue(repository.currentMedia) 1062 val recsCommonModel = 1063 MediaCommonModel.MediaRecommendations( 1064 SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) 1065 ) 1066 val controlCommonModel = 1067 MediaCommonModel.MediaControl( 1068 MediaDataLoadingModel.Loaded(dataMain.instanceId), 1069 true 1070 ) 1071 // WHEN we have media that was recently played, but not currently active 1072 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 1073 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 1074 repository.setOrderedMedia() 1075 1076 verify(listener) 1077 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 1078 verify(mediaLoadingLogger) 1079 .logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString()) 1080 assertThat(currentMedia).containsExactly(controlCommonModel) 1081 1082 // AND we get a smartspace signal with extra to trigger resume 1083 runCurrent() 1084 val extras = Bundle().apply { putBoolean(EXTRA_KEY_TRIGGER_RESUME, true) } 1085 whenever(cardAction.extras).thenReturn(extras) 1086 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 1087 1088 // THEN we should treat the media as active instead 1089 val dataCurrentAndActive = dataCurrent.copy(active = true) 1090 verify(listener) 1091 .onMediaDataLoaded( 1092 eq(KEY), 1093 eq(KEY), 1094 eq(dataCurrentAndActive), 1095 eq(true), 1096 eq(100), 1097 eq(true) 1098 ) 1099 verify(mediaLoadingLogger) 1100 .logMediaLoaded( 1101 eq(dataCurrentAndActive.instanceId), 1102 eq(dataCurrentAndActive.active), 1103 anyString() 1104 ) 1105 assertThat(currentMedia).containsExactly(controlCommonModel, recsCommonModel) 1106 assertThat( 1107 hasActiveMediaOrRecommendation( 1108 selectedUserEntries, 1109 smartspaceMediaData, 1110 reactivatedKey 1111 ) 1112 ) 1113 .isTrue() 1114 // And update the smartspace data state, but not prioritized 1115 verify(listener) 1116 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) 1117 verify(mediaLoadingLogger) 1118 .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString()) 1119 } 1120 1121 @Test smartspaceLoaded_notShouldTriggerResume_doesNotTriggernull1122 fun smartspaceLoaded_notShouldTriggerResume_doesNotTrigger() = 1123 testScope.runTest { 1124 val currentMedia by collectLastValue(repository.currentMedia) 1125 val recsCommonModel = 1126 MediaCommonModel.MediaRecommendations( 1127 SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) 1128 ) 1129 val controlCommonModel = 1130 MediaCommonModel.MediaControl( 1131 MediaDataLoadingModel.Loaded(dataMain.instanceId), 1132 true 1133 ) 1134 1135 // WHEN we have media that was recently played, but not currently active 1136 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 1137 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 1138 repository.setOrderedMedia() 1139 1140 verify(listener) 1141 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 1142 verify(mediaLoadingLogger) 1143 .logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString()) 1144 assertThat(currentMedia).containsExactly(controlCommonModel) 1145 1146 reset(mediaLoadingLogger) 1147 1148 // AND we get a smartspace signal with extra to not trigger resume 1149 val extras = Bundle().apply { putBoolean(EXTRA_KEY_TRIGGER_RESUME, false) } 1150 whenever(cardAction.extras).thenReturn(extras) 1151 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 1152 1153 // THEN listeners are not updated to show media 1154 verify(listener, never()) 1155 .onMediaDataLoaded(eq(KEY), eq(KEY), any(), eq(true), eq(100), eq(true)) 1156 verify(mediaLoadingLogger, never()) 1157 .logMediaLoaded(eq(dataCurrent.instanceId), anyBoolean(), anyString()) 1158 // But the smartspace update is still propagated 1159 verify(listener) 1160 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) 1161 verify(mediaLoadingLogger) 1162 .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString()) 1163 assertThat(currentMedia).containsExactly(controlCommonModel, recsCommonModel) 1164 } 1165 hasActiveMediaOrRecommendationnull1166 private fun hasActiveMediaOrRecommendation( 1167 entries: Map<InstanceId, MediaData>?, 1168 smartspaceMediaData: SmartspaceMediaData?, 1169 reactivatedId: InstanceId? 1170 ): Boolean { 1171 if (entries == null || smartspaceMediaData == null) { 1172 return false 1173 } 1174 return entries.any { it.value.active } || 1175 (smartspaceMediaData.isActive && 1176 (smartspaceMediaData.isValid() || reactivatedId != null)) 1177 } 1178 hasActiveMedianull1179 private fun hasActiveMedia(entries: Map<InstanceId, MediaData>?): Boolean { 1180 return entries?.any { it.value.active } ?: false 1181 } 1182 hasAnyMediaOrRecommendationnull1183 private fun hasAnyMediaOrRecommendation( 1184 entries: Map<InstanceId, MediaData>?, 1185 smartspaceMediaData: SmartspaceMediaData? 1186 ): Boolean { 1187 if (entries == null || smartspaceMediaData == null) { 1188 return false 1189 } 1190 return entries.isNotEmpty() || 1191 (if (mediaFlags.isPersistentSsCardEnabled()) { 1192 smartspaceMediaData.isValid() 1193 } else { 1194 smartspaceMediaData.isActive && smartspaceMediaData.isValid() 1195 }) 1196 } 1197 hasAnyMedianull1198 private fun hasAnyMedia(entries: Map<InstanceId, MediaData>?): Boolean { 1199 return entries?.isNotEmpty() ?: false 1200 } 1201 } 1202