Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 046a0f25 authored by Darrell Shi's avatar Darrell Shi Committed by Android (Google) Code Review
Browse files

Merge "Dynamically size and order ongoing content" into main

parents 4b7074b9 417ff972
Loading
Loading
Loading
Loading
+29 −41
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -25,13 +25,13 @@ import com.android.systemui.media.controls.pipeline.MediaDataManager
import com.android.systemui.util.mockito.KotlinArgumentCaptor
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
@@ -59,74 +59,62 @@ class CommunalMediaRepositoryImplTest : SysuiTestCase() {
    }

    @Test
    fun mediaPlaying_defaultsToFalse() =
    fun hasAnyMediaOrRecommendation_defaultsToFalse() =
        testScope.runTest {
            mediaRepository = CommunalMediaRepositoryImpl(mediaDataManager)

            val isMediaPlaying = collectLastValue(mediaRepository.mediaPlaying)
            val mediaModel = collectLastValue(mediaRepository.mediaModel)
            runCurrent()
            assertThat(isMediaPlaying()).isFalse()
            assertThat(mediaModel()?.hasAnyMediaOrRecommendation).isFalse()
        }

    @Test
    fun mediaPlaying_emitsInitialValue() =
    fun mediaModel_updatesWhenMediaDataLoaded() =
        testScope.runTest {
            // Start with media available.
            whenever(mediaDataManager.hasAnyMediaOrRecommendation()).thenReturn(true)

            mediaRepository = CommunalMediaRepositoryImpl(mediaDataManager)

            val isMediaPlaying = collectLastValue(mediaRepository.mediaPlaying)
            runCurrent()
            assertThat(isMediaPlaying()).isTrue()
        }

    @Test
    fun mediaPlaying_updatesWhenMediaDataLoaded() =
        testScope.runTest {
            mediaRepository = CommunalMediaRepositoryImpl(mediaDataManager)
            // Listener is added
            verify(mediaDataManager).addListener(mediaDataListenerCaptor.capture())

            // Initial value is false.
            var isMediaPlaying = collectLastValue(mediaRepository.mediaPlaying)
            val mediaModel = collectLastValue(mediaRepository.mediaModel)
            runCurrent()
            assertThat(isMediaPlaying()).isFalse()

            // Listener is added
            verify(mediaDataManager).addListener(mediaDataListenerCaptor.capture())
            assertThat(mediaModel()?.hasAnyMediaOrRecommendation).isFalse()

            // Change to media available and notify the listener.
            whenever(mediaDataManager.hasAnyMediaOrRecommendation()).thenReturn(true)
            whenever(mediaData.createdTimestampMillis).thenReturn(1234L)
            mediaDataListenerCaptor.value.onMediaDataLoaded("key", null, mediaData)

            // mediaPlaying now returns true.
            isMediaPlaying = collectLastValue(mediaRepository.mediaPlaying)
            runCurrent()
            assertThat(isMediaPlaying()).isTrue()

            // Media active now returns true.
            assertThat(mediaModel()?.hasAnyMediaOrRecommendation).isTrue()
            assertThat(mediaModel()?.createdTimestampMillis).isEqualTo(1234L)
        }

    @Test
    fun mediaPlaying_updatesWhenMediaDataRemoved() =
    fun mediaModel_updatesWhenMediaDataRemoved() =
        testScope.runTest {
            // Start with media available.
            whenever(mediaDataManager.hasAnyMediaOrRecommendation()).thenReturn(true)

            mediaRepository = CommunalMediaRepositoryImpl(mediaDataManager)

            // Initial value is true.
            var isMediaPlaying = collectLastValue(mediaRepository.mediaPlaying)
            // Listener is added
            verify(mediaDataManager).addListener(mediaDataListenerCaptor.capture())

            // Change to media available and notify the listener.
            whenever(mediaDataManager.hasAnyMediaOrRecommendation()).thenReturn(true)
            mediaDataListenerCaptor.value.onMediaDataLoaded("key", null, mediaData)
            runCurrent()
            assertThat(isMediaPlaying()).isTrue()

            // Listener is added.
            verify(mediaDataManager).addListener(mediaDataListenerCaptor.capture())
            // Media active now returns true.
            val mediaModel = collectLastValue(mediaRepository.mediaModel)
            assertThat(mediaModel()?.hasAnyMediaOrRecommendation).isTrue()

            // Change to media unavailable and notify the listener.
            whenever(mediaDataManager.hasAnyMediaOrRecommendation()).thenReturn(false)
            mediaDataListenerCaptor.value.onMediaDataLoaded("key", null, mediaData)

            // mediaPlaying now returns false.
            isMediaPlaying = collectLastValue(mediaRepository.mediaPlaying)
            mediaDataListenerCaptor.value.onMediaDataRemoved("key")
            runCurrent()
            assertThat(isMediaPlaying()).isFalse()

            // Media active now returns false.
            assertThat(mediaModel()?.hasAnyMediaOrRecommendation).isFalse()
        }
}
+64 −17
Original line number Diff line number Diff line
@@ -148,25 +148,29 @@ class CommunalInteractorTest : SysuiTestCase() {
            whenever(target1.smartspaceTargetId).thenReturn("target1")
            whenever(target1.featureType).thenReturn(SmartspaceTarget.FEATURE_WEATHER)
            whenever(target1.remoteViews).thenReturn(mock(RemoteViews::class.java))
            whenever(target1.creationTimeMillis).thenReturn(0L)

            // Does not have RemoteViews
            val target2 = mock(SmartspaceTarget::class.java)
            whenever(target1.smartspaceTargetId).thenReturn("target2")
            whenever(target1.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
            whenever(target1.remoteViews).thenReturn(null)
            whenever(target2.smartspaceTargetId).thenReturn("target2")
            whenever(target2.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
            whenever(target2.remoteViews).thenReturn(null)
            whenever(target2.creationTimeMillis).thenReturn(0L)

            // Timer and has RemoteViews
            val target3 = mock(SmartspaceTarget::class.java)
            whenever(target1.smartspaceTargetId).thenReturn("target3")
            whenever(target1.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
            whenever(target1.remoteViews).thenReturn(mock(RemoteViews::class.java))
            whenever(target3.smartspaceTargetId).thenReturn("target3")
            whenever(target3.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
            whenever(target3.remoteViews).thenReturn(mock(RemoteViews::class.java))
            whenever(target3.creationTimeMillis).thenReturn(0L)

            val targets = listOf(target1, target2, target3)
            smartspaceRepository.setCommunalSmartspaceTargets(targets)

            val smartspaceContent by collectLastValue(underTest.smartspaceContent)
            val smartspaceContent by collectLastValue(underTest.ongoingContent)
            assertThat(smartspaceContent?.size).isEqualTo(1)
            assertThat(smartspaceContent?.get(0)?.key).isEqualTo("smartspace_target3")
            assertThat(smartspaceContent?.get(0)?.key)
                .isEqualTo(CommunalContentModel.KEY.smartspace("target3"))
        }

    @Test
@@ -256,16 +260,12 @@ class CommunalInteractorTest : SysuiTestCase() {

            val targets = mutableListOf<SmartspaceTarget>()
            for (index in 0 until totalTargets) {
                val target = mock(SmartspaceTarget::class.java)
                whenever(target.smartspaceTargetId).thenReturn("target$index")
                whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
                whenever(target.remoteViews).thenReturn(mock(RemoteViews::class.java))
                targets.add(target)
                targets.add(smartspaceTimer(index.toString()))
            }

            smartspaceRepository.setCommunalSmartspaceTargets(targets)

            val smartspaceContent by collectLastValue(underTest.smartspaceContent)
            val smartspaceContent by collectLastValue(underTest.ongoingContent)
            assertThat(smartspaceContent?.size).isEqualTo(totalTargets)
            for (index in 0 until totalTargets) {
                assertThat(smartspaceContent?.get(index)?.size).isEqualTo(expectedSizes[index])
@@ -279,13 +279,51 @@ class CommunalInteractorTest : SysuiTestCase() {
            tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)

            // Media is playing.
            mediaRepository.mediaPlaying.value = true
            mediaRepository.mediaActive()

            val umoContent by collectLastValue(underTest.umoContent)
            val umoContent by collectLastValue(underTest.ongoingContent)

            assertThat(umoContent?.size).isEqualTo(1)
            assertThat(umoContent?.get(0)).isInstanceOf(CommunalContentModel.Umo::class.java)
            assertThat(umoContent?.get(0)?.key).isEqualTo(CommunalContentModel.UMO_KEY)
            assertThat(umoContent?.get(0)?.key).isEqualTo(CommunalContentModel.KEY.umo())
        }

    @Test
    fun ongoing_shouldOrderAndSizeByTimestamp() =
        testScope.runTest {
            // Keyguard showing, and tutorial completed.
            keyguardRepository.setKeyguardShowing(true)
            keyguardRepository.setKeyguardOccluded(false)
            tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)

            // Timer1 started
            val timer1 = smartspaceTimer("timer1", timestamp = 1L)
            smartspaceRepository.setCommunalSmartspaceTargets(listOf(timer1))

            // Umo started
            mediaRepository.mediaActive(timestamp = 2L)

            // Timer2 started
            val timer2 = smartspaceTimer("timer2", timestamp = 3L)
            smartspaceRepository.setCommunalSmartspaceTargets(listOf(timer1, timer2))

            // Timer3 started
            val timer3 = smartspaceTimer("timer3", timestamp = 4L)
            smartspaceRepository.setCommunalSmartspaceTargets(listOf(timer1, timer2, timer3))

            val ongoingContent by collectLastValue(underTest.ongoingContent)
            assertThat(ongoingContent?.size).isEqualTo(4)
            assertThat(ongoingContent?.get(0)?.key)
                .isEqualTo(CommunalContentModel.KEY.smartspace("timer3"))
            assertThat(ongoingContent?.get(0)?.size).isEqualTo(CommunalContentSize.FULL)
            assertThat(ongoingContent?.get(1)?.key)
                .isEqualTo(CommunalContentModel.KEY.smartspace("timer2"))
            assertThat(ongoingContent?.get(1)?.size).isEqualTo(CommunalContentSize.THIRD)
            assertThat(ongoingContent?.get(2)?.key).isEqualTo(CommunalContentModel.KEY.umo())
            assertThat(ongoingContent?.get(2)?.size).isEqualTo(CommunalContentSize.THIRD)
            assertThat(ongoingContent?.get(3)?.key)
                .isEqualTo(CommunalContentModel.KEY.smartspace("timer1"))
            assertThat(ongoingContent?.get(3)?.size).isEqualTo(CommunalContentSize.THIRD)
        }

    @Test
@@ -334,4 +372,13 @@ class CommunalInteractorTest : SysuiTestCase() {
            underTest.showWidgetEditor()
            verify(editWidgetsActivityStarter).startActivity()
        }

    private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget {
        val timer = mock(SmartspaceTarget::class.java)
        whenever(timer.smartspaceTargetId).thenReturn(id)
        whenever(timer.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
        whenever(timer.remoteViews).thenReturn(mock(RemoteViews::class.java))
        whenever(timer.creationTimeMillis).thenReturn(timestamp)
        return timer
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -119,7 +119,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
            smartspaceRepository.setCommunalSmartspaceTargets(listOf(target))

            // Media playing.
            mediaRepository.mediaPlaying.value = true
            mediaRepository.mediaActive()

            val communalContent by collectLastValue(underTest.communalContent)

+1 −1
Original line number Diff line number Diff line
@@ -140,7 +140,7 @@ class CommunalViewModelTest : SysuiTestCase() {
            smartspaceRepository.setCommunalSmartspaceTargets(listOf(target))

            // Media playing.
            mediaRepository.mediaPlaying.value = true
            mediaRepository.mediaActive()

            val communalContent by collectLastValue(underTest.communalContent)

+30 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.communal.data.model

/** Data model of media on the communal hub. */
data class CommunalMediaModel(
    val hasAnyMediaOrRecommendation: Boolean,
    val createdTimestampMillis: Long = 0L,
) {
    companion object {
        val INACTIVE =
            CommunalMediaModel(
                hasAnyMediaOrRecommendation = false,
            )
    }
}
Loading