1 /* 2 * Copyright (C) 2020 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.media.controls.MediaTestUtils 28 import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_RESUME 29 import com.android.systemui.media.controls.shared.model.MediaData 30 import com.android.systemui.media.controls.shared.model.SmartspaceMediaData 31 import com.android.systemui.media.controls.ui.controller.MediaPlayerData 32 import com.android.systemui.media.controls.util.MediaFlags 33 import com.android.systemui.media.controls.util.MediaUiEventLogger 34 import com.android.systemui.settings.UserTracker 35 import com.android.systemui.statusbar.NotificationLockscreenUserManager 36 import com.android.systemui.util.time.FakeSystemClock 37 import com.google.common.truth.Truth.assertThat 38 import java.util.concurrent.Executor 39 import org.junit.Before 40 import org.junit.Test 41 import org.junit.runner.RunWith 42 import org.mockito.ArgumentMatchers.anyBoolean 43 import org.mockito.ArgumentMatchers.anyInt 44 import org.mockito.ArgumentMatchers.anyLong 45 import org.mockito.Mock 46 import org.mockito.Mockito.never 47 import org.mockito.Mockito.reset 48 import org.mockito.Mockito.verify 49 import org.mockito.MockitoAnnotations 50 import org.mockito.kotlin.any 51 import org.mockito.kotlin.eq 52 import org.mockito.kotlin.whenever 53 54 private const val KEY = "TEST_KEY" 55 private const val KEY_ALT = "TEST_KEY_2" 56 private const val USER_MAIN = 0 57 private const val USER_GUEST = 10 58 private const val PRIVATE_PROFILE = 12 59 private const val PACKAGE = "PKG" 60 private val INSTANCE_ID = InstanceId.fakeInstanceId(123)!! 61 private const val APP_UID = 99 62 private const val SMARTSPACE_KEY = "SMARTSPACE_KEY" 63 private const val SMARTSPACE_PACKAGE = "SMARTSPACE_PKG" 64 private val SMARTSPACE_INSTANCE_ID = InstanceId.fakeInstanceId(456)!! 65 66 @SmallTest 67 @RunWith(AndroidJUnit4::class) 68 @TestableLooper.RunWithLooper 69 class LegacyMediaDataFilterImplTest : SysuiTestCase() { 70 71 @Mock private lateinit var listener: MediaDataManager.Listener 72 @Mock private lateinit var userTracker: UserTracker 73 @Mock private lateinit var broadcastSender: BroadcastSender 74 @Mock private lateinit var mediaDataManager: MediaDataManager 75 @Mock private lateinit var lockscreenUserManager: NotificationLockscreenUserManager 76 @Mock private lateinit var executor: Executor 77 @Mock private lateinit var smartspaceData: SmartspaceMediaData 78 @Mock private lateinit var smartspaceMediaRecommendationItem: SmartspaceAction 79 @Mock private lateinit var logger: MediaUiEventLogger 80 @Mock private lateinit var mediaFlags: MediaFlags 81 @Mock private lateinit var cardAction: SmartspaceAction 82 83 private lateinit var mediaDataFilter: LegacyMediaDataFilterImpl 84 private lateinit var dataMain: MediaData 85 private lateinit var dataGuest: MediaData 86 private lateinit var dataPrivateProfile: MediaData 87 private val clock = FakeSystemClock() 88 89 @Before setupnull90 fun setup() { 91 MockitoAnnotations.initMocks(this) 92 MediaPlayerData.clear() 93 whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false) 94 mediaDataFilter = 95 LegacyMediaDataFilterImpl( 96 context, 97 userTracker, 98 broadcastSender, 99 lockscreenUserManager, 100 executor, 101 clock, 102 logger, 103 mediaFlags 104 ) 105 mediaDataFilter.mediaDataManager = mediaDataManager 106 mediaDataFilter.addListener(listener) 107 108 // Start all tests as main user 109 setUser(USER_MAIN) 110 111 // Set up test media data 112 dataMain = 113 MediaTestUtils.emptyMediaData.copy( 114 userId = USER_MAIN, 115 packageName = PACKAGE, 116 instanceId = INSTANCE_ID, 117 appUid = APP_UID 118 ) 119 dataGuest = dataMain.copy(userId = USER_GUEST) 120 dataPrivateProfile = dataMain.copy(userId = PRIVATE_PROFILE) 121 122 whenever(smartspaceData.targetId).thenReturn(SMARTSPACE_KEY) 123 whenever(smartspaceData.isActive).thenReturn(true) 124 whenever(smartspaceData.isValid()).thenReturn(true) 125 whenever(smartspaceData.packageName).thenReturn(SMARTSPACE_PACKAGE) 126 whenever(smartspaceData.recommendations) 127 .thenReturn(listOf(smartspaceMediaRecommendationItem)) 128 whenever(smartspaceData.headphoneConnectionTimeMillis) 129 .thenReturn(clock.currentTimeMillis() - 100) 130 whenever(smartspaceData.instanceId).thenReturn(SMARTSPACE_INSTANCE_ID) 131 whenever(smartspaceData.cardAction).thenReturn(cardAction) 132 } 133 setUsernull134 private fun setUser(id: Int) { 135 whenever(lockscreenUserManager.isCurrentProfile(anyInt())).thenReturn(false) 136 whenever(lockscreenUserManager.isProfileAvailable(anyInt())).thenReturn(false) 137 whenever(lockscreenUserManager.isCurrentProfile(eq(id))).thenReturn(true) 138 whenever(lockscreenUserManager.isProfileAvailable(eq(id))).thenReturn(true) 139 whenever(lockscreenUserManager.isProfileAvailable(eq(PRIVATE_PROFILE))).thenReturn(true) 140 mediaDataFilter.handleUserSwitched() 141 } 142 setPrivateProfileUnavailablenull143 private fun setPrivateProfileUnavailable() { 144 whenever(lockscreenUserManager.isCurrentProfile(anyInt())).thenReturn(false) 145 whenever(lockscreenUserManager.isCurrentProfile(eq(USER_MAIN))).thenReturn(true) 146 whenever(lockscreenUserManager.isCurrentProfile(eq(PRIVATE_PROFILE))).thenReturn(true) 147 whenever(lockscreenUserManager.isProfileAvailable(eq(PRIVATE_PROFILE))).thenReturn(false) 148 mediaDataFilter.handleProfileChanged() 149 } 150 151 @Test testOnDataLoadedForCurrentUser_callsListenernull152 fun testOnDataLoadedForCurrentUser_callsListener() { 153 // GIVEN a media for main user 154 mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) 155 156 // THEN we should tell the listener 157 verify(listener) 158 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataMain), eq(true), eq(0), eq(false)) 159 } 160 161 @Test testOnDataLoadedForGuest_doesNotCallListenernull162 fun testOnDataLoadedForGuest_doesNotCallListener() { 163 // GIVEN a media for guest user 164 mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest) 165 166 // THEN we should NOT tell the listener 167 verify(listener, never()) 168 .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean()) 169 } 170 171 @Test testOnRemovedForCurrent_callsListenernull172 fun testOnRemovedForCurrent_callsListener() { 173 // GIVEN a media was removed for main user 174 mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) 175 mediaDataFilter.onMediaDataRemoved(KEY, false) 176 177 // THEN we should tell the listener 178 verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) 179 } 180 181 @Test testOnRemovedForGuest_doesNotCallListenernull182 fun testOnRemovedForGuest_doesNotCallListener() { 183 // GIVEN a media was removed for guest user 184 mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest) 185 mediaDataFilter.onMediaDataRemoved(KEY, false) 186 187 // THEN we should NOT tell the listener 188 verify(listener, never()).onMediaDataRemoved(eq(KEY), anyBoolean()) 189 } 190 191 @Test testOnUserSwitched_removesOldUserControlsnull192 fun testOnUserSwitched_removesOldUserControls() { 193 // GIVEN that we have a media loaded for main user 194 mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) 195 196 // and we switch to guest user 197 setUser(USER_GUEST) 198 199 // THEN we should remove the main user's media 200 verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) 201 } 202 203 @Test testOnUserSwitched_addsNewUserControlsnull204 fun testOnUserSwitched_addsNewUserControls() { 205 // GIVEN that we had some media for both users 206 mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) 207 mediaDataFilter.onMediaDataLoaded(KEY_ALT, null, dataGuest) 208 reset(listener) 209 210 // and we switch to guest user 211 setUser(USER_GUEST) 212 213 // THEN we should add back the guest user media 214 verify(listener) 215 .onMediaDataLoaded(eq(KEY_ALT), eq(null), eq(dataGuest), eq(true), eq(0), eq(false)) 216 217 // but not the main user's 218 verify(listener, never()) 219 .onMediaDataLoaded(eq(KEY), any(), eq(dataMain), anyBoolean(), anyInt(), anyBoolean()) 220 } 221 222 @Test testOnProfileChanged_profileUnavailable_loadControlsnull223 fun testOnProfileChanged_profileUnavailable_loadControls() { 224 // GIVEN that we had some media for both profiles 225 mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) 226 mediaDataFilter.onMediaDataLoaded(KEY_ALT, null, dataPrivateProfile) 227 reset(listener) 228 229 // and we change profile status 230 setPrivateProfileUnavailable() 231 232 // THEN we should add the private profile media 233 verify(listener).onMediaDataRemoved(eq(KEY_ALT), eq(false)) 234 } 235 236 @Test hasAnyMedia_noMediaSet_returnsFalsenull237 fun hasAnyMedia_noMediaSet_returnsFalse() { 238 assertThat(mediaDataFilter.hasAnyMedia()).isFalse() 239 } 240 241 @Test hasAnyMedia_mediaSet_returnsTruenull242 fun hasAnyMedia_mediaSet_returnsTrue() { 243 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain) 244 245 assertThat(mediaDataFilter.hasAnyMedia()).isTrue() 246 } 247 248 @Test hasAnyMedia_recommendationSet_returnsFalsenull249 fun hasAnyMedia_recommendationSet_returnsFalse() { 250 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 251 252 assertThat(mediaDataFilter.hasAnyMedia()).isFalse() 253 } 254 255 @Test hasAnyMediaOrRecommendation_noMediaSet_returnsFalsenull256 fun hasAnyMediaOrRecommendation_noMediaSet_returnsFalse() { 257 assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isFalse() 258 } 259 260 @Test hasAnyMediaOrRecommendation_mediaSet_returnsTruenull261 fun hasAnyMediaOrRecommendation_mediaSet_returnsTrue() { 262 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain) 263 264 assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isTrue() 265 } 266 267 @Test hasAnyMediaOrRecommendation_recommendationSet_returnsTruenull268 fun hasAnyMediaOrRecommendation_recommendationSet_returnsTrue() { 269 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 270 271 assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isTrue() 272 } 273 274 @Test hasActiveMedia_noMediaSet_returnsFalsenull275 fun hasActiveMedia_noMediaSet_returnsFalse() { 276 assertThat(mediaDataFilter.hasActiveMedia()).isFalse() 277 } 278 279 @Test hasActiveMedia_inactiveMediaSet_returnsFalsenull280 fun hasActiveMedia_inactiveMediaSet_returnsFalse() { 281 val data = dataMain.copy(active = false) 282 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) 283 284 assertThat(mediaDataFilter.hasActiveMedia()).isFalse() 285 } 286 287 @Test hasActiveMedia_activeMediaSet_returnsTruenull288 fun hasActiveMedia_activeMediaSet_returnsTrue() { 289 val data = dataMain.copy(active = true) 290 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) 291 292 assertThat(mediaDataFilter.hasActiveMedia()).isTrue() 293 } 294 295 @Test hasActiveMediaOrRecommendation_nothingSet_returnsFalsenull296 fun hasActiveMediaOrRecommendation_nothingSet_returnsFalse() { 297 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 298 } 299 300 @Test hasActiveMediaOrRecommendation_inactiveMediaSet_returnsFalsenull301 fun hasActiveMediaOrRecommendation_inactiveMediaSet_returnsFalse() { 302 val data = dataMain.copy(active = false) 303 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) 304 305 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 306 } 307 308 @Test hasActiveMediaOrRecommendation_activeMediaSet_returnsTruenull309 fun hasActiveMediaOrRecommendation_activeMediaSet_returnsTrue() { 310 val data = dataMain.copy(active = true) 311 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) 312 313 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue() 314 } 315 316 @Test hasActiveMediaOrRecommendation_inactiveRecommendationSet_returnsFalsenull317 fun hasActiveMediaOrRecommendation_inactiveRecommendationSet_returnsFalse() { 318 whenever(smartspaceData.isActive).thenReturn(false) 319 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 320 321 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 322 } 323 324 @Test hasActiveMediaOrRecommendation_invalidRecommendationSet_returnsFalsenull325 fun hasActiveMediaOrRecommendation_invalidRecommendationSet_returnsFalse() { 326 whenever(smartspaceData.isValid()).thenReturn(false) 327 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 328 329 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 330 } 331 332 @Test hasActiveMediaOrRecommendation_activeAndValidRecommendationSet_returnsTruenull333 fun hasActiveMediaOrRecommendation_activeAndValidRecommendationSet_returnsTrue() { 334 whenever(smartspaceData.isActive).thenReturn(true) 335 whenever(smartspaceData.isValid()).thenReturn(true) 336 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 337 338 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue() 339 } 340 341 @Test testHasAnyMediaOrRecommendation_onlyCurrentUsernull342 fun testHasAnyMediaOrRecommendation_onlyCurrentUser() { 343 assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isFalse() 344 345 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataGuest) 346 assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isFalse() 347 assertThat(mediaDataFilter.hasAnyMedia()).isFalse() 348 } 349 350 @Test testHasActiveMediaOrRecommendation_onlyCurrentUsernull351 fun testHasActiveMediaOrRecommendation_onlyCurrentUser() { 352 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 353 val data = dataGuest.copy(active = true) 354 355 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) 356 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 357 assertThat(mediaDataFilter.hasAnyMedia()).isFalse() 358 } 359 360 @Test testOnNotificationRemoved_doesntHaveMedianull361 fun testOnNotificationRemoved_doesntHaveMedia() { 362 mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain) 363 mediaDataFilter.onMediaDataRemoved(KEY, false) 364 assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isFalse() 365 assertThat(mediaDataFilter.hasAnyMedia()).isFalse() 366 } 367 368 @Test testOnSwipeToDismiss_setsTimedOutnull369 fun testOnSwipeToDismiss_setsTimedOut() { 370 mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) 371 mediaDataFilter.onSwipeToDismiss() 372 373 verify(mediaDataManager).setInactive(eq(KEY), eq(true), eq(true)) 374 } 375 376 @Test testOnSmartspaceMediaDataLoaded_noMedia_activeValidRec_prioritizesSmartspacenull377 fun testOnSmartspaceMediaDataLoaded_noMedia_activeValidRec_prioritizesSmartspace() { 378 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 379 380 verify(listener) 381 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true)) 382 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue() 383 assertThat(mediaDataFilter.hasActiveMedia()).isFalse() 384 verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID) 385 verify(logger, never()).logRecommendationActivated(any(), any(), any()) 386 } 387 388 @Test testOnSmartspaceMediaDataLoaded_noMedia_inactiveRec_showsNothingnull389 fun testOnSmartspaceMediaDataLoaded_noMedia_inactiveRec_showsNothing() { 390 whenever(smartspaceData.isActive).thenReturn(false) 391 392 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 393 394 verify(listener, never()) 395 .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean()) 396 verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean()) 397 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 398 assertThat(mediaDataFilter.hasActiveMedia()).isFalse() 399 verify(logger, never()).logRecommendationAdded(any(), any()) 400 verify(logger, never()).logRecommendationActivated(any(), any(), any()) 401 } 402 403 @Test testOnSmartspaceMediaDataLoaded_noRecentMedia_activeValidRec_prioritizesSmartspacenull404 fun testOnSmartspaceMediaDataLoaded_noRecentMedia_activeValidRec_prioritizesSmartspace() { 405 val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 406 mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld) 407 clock.advanceTime(SMARTSPACE_MAX_AGE + 100) 408 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 409 410 verify(listener) 411 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true)) 412 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue() 413 assertThat(mediaDataFilter.hasActiveMedia()).isFalse() 414 verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID) 415 verify(logger, never()).logRecommendationActivated(any(), any(), any()) 416 } 417 418 @Test testOnSmartspaceMediaDataLoaded_noRecentMedia_inactiveRec_showsNothingnull419 fun testOnSmartspaceMediaDataLoaded_noRecentMedia_inactiveRec_showsNothing() { 420 whenever(smartspaceData.isActive).thenReturn(false) 421 422 val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 423 mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld) 424 clock.advanceTime(SMARTSPACE_MAX_AGE + 100) 425 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 426 427 verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean()) 428 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 429 assertThat(mediaDataFilter.hasActiveMedia()).isFalse() 430 verify(logger, never()).logRecommendationAdded(any(), any()) 431 verify(logger, never()).logRecommendationActivated(any(), any(), any()) 432 } 433 434 @Test testOnSmartspaceMediaDataLoaded_hasRecentMedia_inactiveRec_showsNothingnull435 fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_inactiveRec_showsNothing() { 436 whenever(smartspaceData.isActive).thenReturn(false) 437 438 // WHEN we have media that was recently played, but not currently active 439 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 440 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 441 verify(listener) 442 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 443 444 // AND we get a smartspace signal 445 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 446 447 // THEN we should tell listeners to treat the media as not active instead 448 verify(listener, never()) 449 .onMediaDataLoaded(eq(KEY), eq(KEY), any(), anyBoolean(), anyInt(), anyBoolean()) 450 verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean()) 451 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 452 assertThat(mediaDataFilter.hasActiveMedia()).isFalse() 453 verify(logger, never()).logRecommendationAdded(any(), any()) 454 verify(logger, never()).logRecommendationActivated(any(), any(), any()) 455 } 456 457 @Test testOnSmartspaceMediaDataLoaded_hasRecentMedia_activeInvalidRec_usesMedianull458 fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_activeInvalidRec_usesMedia() { 459 whenever(smartspaceData.isValid()).thenReturn(false) 460 461 // WHEN we have media that was recently played, but not currently active 462 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 463 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 464 verify(listener) 465 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 466 467 // AND we get a smartspace signal 468 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 469 470 // THEN we should tell listeners to treat the media as active instead 471 val dataCurrentAndActive = dataCurrent.copy(active = true) 472 verify(listener) 473 .onMediaDataLoaded( 474 eq(KEY), 475 eq(KEY), 476 eq(dataCurrentAndActive), 477 eq(true), 478 eq(100), 479 eq(true) 480 ) 481 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue() 482 // Smartspace update shouldn't be propagated for the empty rec list. 483 verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean()) 484 verify(logger, never()).logRecommendationAdded(any(), any()) 485 verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID)) 486 } 487 488 @Test testOnSmartspaceMediaDataLoaded_hasRecentMedia_activeValidRec_usesBothnull489 fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_activeValidRec_usesBoth() { 490 // WHEN we have media that was recently played, but not currently active 491 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 492 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 493 verify(listener) 494 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 495 496 // AND we get a smartspace signal 497 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 498 499 // THEN we should tell listeners to treat the media as active instead 500 val dataCurrentAndActive = dataCurrent.copy(active = true) 501 verify(listener) 502 .onMediaDataLoaded( 503 eq(KEY), 504 eq(KEY), 505 eq(dataCurrentAndActive), 506 eq(true), 507 eq(100), 508 eq(true) 509 ) 510 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue() 511 // Smartspace update should also be propagated but not prioritized. 512 verify(listener) 513 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) 514 verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID) 515 verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID)) 516 } 517 518 @Test testOnSmartspaceMediaDataRemoved_usedSmartspace_clearsSmartspacenull519 fun testOnSmartspaceMediaDataRemoved_usedSmartspace_clearsSmartspace() { 520 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 521 mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) 522 523 verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) 524 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 525 assertThat(mediaDataFilter.hasActiveMedia()).isFalse() 526 } 527 528 @Test testOnSmartspaceMediaDataRemoved_usedMediaAndSmartspace_clearsBothnull529 fun testOnSmartspaceMediaDataRemoved_usedMediaAndSmartspace_clearsBoth() { 530 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 531 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 532 verify(listener) 533 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 534 535 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 536 537 val dataCurrentAndActive = dataCurrent.copy(active = true) 538 verify(listener) 539 .onMediaDataLoaded( 540 eq(KEY), 541 eq(KEY), 542 eq(dataCurrentAndActive), 543 eq(true), 544 eq(100), 545 eq(true) 546 ) 547 548 mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) 549 550 verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) 551 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 552 assertThat(mediaDataFilter.hasActiveMedia()).isFalse() 553 } 554 555 @Test testOnSmartspaceLoaded_persistentEnabled_isInactive_notifiesListenersnull556 fun testOnSmartspaceLoaded_persistentEnabled_isInactive_notifiesListeners() { 557 whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(true) 558 whenever(smartspaceData.isActive).thenReturn(false) 559 560 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 561 562 verify(listener) 563 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) 564 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 565 assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isTrue() 566 } 567 568 @Test testOnSmartspaceLoaded_persistentEnabled_inactive_hasRecentMedia_staysInactivenull569 fun testOnSmartspaceLoaded_persistentEnabled_inactive_hasRecentMedia_staysInactive() { 570 whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(true) 571 whenever(smartspaceData.isActive).thenReturn(false) 572 573 // If there is media that was recently played but inactive 574 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 575 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 576 verify(listener) 577 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 578 579 // And an inactive recommendation is loaded 580 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 581 582 // Smartspace is loaded but the media stays inactive 583 verify(listener) 584 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) 585 verify(listener, never()) 586 .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean()) 587 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse() 588 assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isTrue() 589 } 590 591 @Test testOnSwipeToDismiss_persistentEnabled_recommendationSetInactivenull592 fun testOnSwipeToDismiss_persistentEnabled_recommendationSetInactive() { 593 whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(true) 594 595 val data = 596 EMPTY_SMARTSPACE_MEDIA_DATA.copy( 597 targetId = SMARTSPACE_KEY, 598 isActive = true, 599 packageName = SMARTSPACE_PACKAGE, 600 recommendations = listOf(smartspaceMediaRecommendationItem), 601 ) 602 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, data) 603 mediaDataFilter.onSwipeToDismiss() 604 605 verify(mediaDataManager).setRecommendationInactive(eq(SMARTSPACE_KEY)) 606 verify(mediaDataManager, never()) 607 .dismissSmartspaceRecommendation(eq(SMARTSPACE_KEY), anyLong()) 608 } 609 610 @Test testSmartspaceLoaded_shouldTriggerResume_doesTriggernull611 fun testSmartspaceLoaded_shouldTriggerResume_doesTrigger() { 612 // WHEN we have media that was recently played, but not currently active 613 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 614 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 615 verify(listener) 616 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 617 618 // AND we get a smartspace signal with extra to trigger resume 619 val extras = Bundle().apply { putBoolean(EXTRA_KEY_TRIGGER_RESUME, true) } 620 whenever(cardAction.extras).thenReturn(extras) 621 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 622 623 // THEN we should tell listeners to treat the media as active instead 624 val dataCurrentAndActive = dataCurrent.copy(active = true) 625 verify(listener) 626 .onMediaDataLoaded( 627 eq(KEY), 628 eq(KEY), 629 eq(dataCurrentAndActive), 630 eq(true), 631 eq(100), 632 eq(true) 633 ) 634 assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue() 635 // And send the smartspace data, but not prioritized 636 verify(listener) 637 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) 638 } 639 640 @Test testSmartspaceLoaded_notShouldTriggerResume_doesNotTriggernull641 fun testSmartspaceLoaded_notShouldTriggerResume_doesNotTrigger() { 642 // WHEN we have media that was recently played, but not currently active 643 val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) 644 mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) 645 verify(listener) 646 .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) 647 648 // AND we get a smartspace signal with extra to not trigger resume 649 val extras = Bundle().apply { putBoolean(EXTRA_KEY_TRIGGER_RESUME, false) } 650 whenever(cardAction.extras).thenReturn(extras) 651 mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 652 653 // THEN listeners are not updated to show media 654 verify(listener, never()) 655 .onMediaDataLoaded(eq(KEY), eq(KEY), any(), eq(true), eq(100), eq(true)) 656 // But the smartspace update is still propagated 657 verify(listener) 658 .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) 659 } 660 } 661