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

Commit d1a06ac0 authored by Sandeep's avatar Sandeep Committed by Sandeep Suman
Browse files

Fixed test for volume sliders and media output component

Bug: b/364012613
Test: MediaOutputComponentMotionTest, VolumeSlidersComponentMotionTest
Flag: TEST_ONLY

Change-Id: I8004edc3f56880337a754e59e162135cefd28f92
parent 22a4b30f
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ import androidx.compose.ui.semantics.testTagsAsResourceId
 */
@Stable
fun Modifier.sysuiResTag(resId: String): Modifier {
    return this.testTag("com.android.systemui:id/$resId")
    return this.testTag(resIdToTestTag(resId))
}

/** Mark this node as a container that contains one or more [sysuiResTag] descendants. */
@@ -41,4 +41,10 @@ fun Modifier.sysUiResTagContainer(): Modifier {
    return this.then(TestTagAsResourceIdModifier)
}

/**
 * Converts a simple resource ID name string into a fully qualified resource name string, formatted
 * for use as a test tag within the Android SystemUI package.
 */
fun resIdToTestTag(resId: String): String = "com.android.systemui:id/$resId"

private val TestTagAsResourceIdModifier = Modifier.semantics { testTagsAsResourceId = true }
+59 −19
Original line number Diff line number Diff line
@@ -45,7 +45,9 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@@ -58,6 +60,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.Expandable
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.common.ui.compose.toColor
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.res.R
import com.android.systemui.volume.panel.component.mediaoutput.ui.viewmodel.ConnectedDeviceViewModel
import com.android.systemui.volume.panel.component.mediaoutput.ui.viewmodel.DeviceIconViewModel
@@ -65,14 +68,15 @@ import com.android.systemui.volume.panel.component.mediaoutput.ui.viewmodel.Medi
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent
import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope
import com.google.common.annotations.VisibleForTesting
import java.util.Objects
import javax.inject.Inject
import platform.test.motion.compose.values.MotionTestValueKey
import platform.test.motion.compose.values.motionTestValues

@VolumePanelScope
class MediaOutputComponent
@Inject
constructor(
    private val viewModel: MediaOutputViewModel,
) : ComposeVolumePanelUiComponent {
class MediaOutputComponent @Inject constructor(private val viewModel: MediaOutputViewModel) :
    ComposeVolumePanelUiComponent {

    @Composable
    override fun VolumePanelComposeScope.Content(modifier: Modifier) {
@@ -142,9 +146,19 @@ constructor(
    @Composable
    private fun ConnectedDeviceIcon(deviceIconViewModel: DeviceIconViewModel) {
        val transition = updateTransition(deviceIconViewModel, label = "MediaOutputIconTransition")
        val isTransitionIdle by
            remember(transition) {
                derivedStateOf {
                    transition.currentState == transition.targetState && !transition.isRunning
                }
            }
        Box(
            modifier = Modifier.padding(16.dp).fillMaxHeight().aspectRatio(1f),
            contentAlignment = Alignment.Center
            modifier =
                Modifier.padding(16.dp).fillMaxHeight().aspectRatio(1f).motionTestValues {
                    isTransitionIdle exportAs
                        MediaOutputComponentMotionTestKeys.isIconTransitionIdle
                },
            contentAlignment = Alignment.Center,
        ) {
            transition.AnimatedContent(
                contentKey = { it.backgroundColor },
@@ -157,12 +171,10 @@ constructor(
                            fadeOut(animationSpec = snap())
                    } else {
                        fadeIn(animationSpec = snap(delayMillis = 900)) togetherWith
                            scaleOut(
                                targetScale = 0.9f,
                                animationSpec = isPlayingOutSpec(),
                            ) + fadeOut(animationSpec = isPlayingOutSpec())
                    }
                            scaleOut(targetScale = 0.9f, animationSpec = isPlayingOutSpec()) +
                                fadeOut(animationSpec = isPlayingOutSpec())
                    }
                },
            ) { targetViewModel ->
                Spacer(
                    modifier =
@@ -170,11 +182,18 @@ constructor(
                            .background(
                                color = targetViewModel.backgroundColor.toColor(),
                                shape = RoundedCornerShape(12.dp),
                            ),
                            )
                            .sysuiResTag(
                                if (targetViewModel is DeviceIconViewModel.IsPlaying) {
                                    MediaOutputComponentMotionTestKeys.PLAYING_ICON_BACKGROUND_TAG
                                } else {
                                    MediaOutputComponentMotionTestKeys.IDLE_ICON_BACKGROUND_TAG
                                }
                            )
                )
            }
            transition.AnimatedContent(
                contentKey = { it.icon },
                contentKey = { Objects.hash(it.icon, it.iconColor) },
                transitionSpec = {
                    if (targetState is DeviceIconViewModel.IsPlaying) {
                        fadeIn(animationSpec = snap(delayMillis = 700)) togetherWith
@@ -189,12 +208,21 @@ constructor(
                        ) + fadeIn(animationSpec = isNotPlayingInIconSpec()) togetherWith
                            fadeOut(animationSpec = isPlayingOutSpec())
                    }
                }
            ) {
                },
            ) { targetViewModel ->
                Icon(
                    icon = it.icon,
                    tint = it.iconColor.toColor(),
                    modifier = Modifier.padding(12.dp).fillMaxSize(),
                    icon = targetViewModel.icon,
                    tint = targetViewModel.iconColor.toColor(),
                    modifier =
                        Modifier.padding(12.dp)
                            .fillMaxSize()
                            .sysuiResTag(
                                if (targetViewModel is DeviceIconViewModel.IsPlaying) {
                                    MediaOutputComponentMotionTestKeys.PLAYING_ICON_TAG
                                } else {
                                    MediaOutputComponentMotionTestKeys.IDLE_ICON_TAG
                                }
                            ),
                )
            }
        }
@@ -210,3 +238,15 @@ private fun <T> isPlayingInIconBackgroundSpec() = tween<T>(durationMillis = 400,
private fun <T> isNotPlayingOutIconSpec() = tween<T>(durationMillis = 400, delayMillis = 300)

private fun <T> isNotPlayingInIconSpec() = tween<T>(durationMillis = 400, delayMillis = 900)

@VisibleForTesting
object MediaOutputComponentMotionTestKeys {

    const val PLAYING_ICON_TAG = "PlayingIcon"
    const val PLAYING_ICON_BACKGROUND_TAG = "PlayingIconBackground"
    const val IDLE_ICON_TAG = "IdleIcon"
    const val IDLE_ICON_BACKGROUND_TAG = "IdleIconBackground"

    val isIconTransitionIdle: MotionTestValueKey<Boolean> =
        MotionTestValueKey("is_icon_transition_idle")
}
+37 −2
Original line number Diff line number Diff line
@@ -41,7 +41,9 @@ import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
@@ -58,8 +60,12 @@ import com.android.compose.PlatformSliderColors
import com.android.compose.modifiers.padding
import com.android.compose.modifiers.thenIf
import com.android.systemui.Flags
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.res.R
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
import com.google.common.annotations.VisibleForTesting
import platform.test.motion.compose.values.MotionTestValueKey
import platform.test.motion.compose.values.motionTestValues

private const val EXPAND_DURATION_MILLIS = 500
private const val COLLAPSE_EXPAND_BUTTON_DELAY_MILLIS = 350
@@ -104,6 +110,11 @@ fun ColumnVolumeSliders(
                    if (Flags.volumeRedesign()) {
                        {
                            ExpandButton(
                                modifier =
                                    Modifier.sysuiResTag(
                                        ColumnVolumeSlidersMotionTestKeys
                                            .TOGGLE_EXPANSION_BUTTON_TAG
                                    ),
                                isExpanded = isExpanded,
                                isExpandable = isExpandable,
                                onExpandedChanged = onExpandedChanged,
@@ -116,7 +127,11 @@ fun ColumnVolumeSliders(

            if (!Flags.volumeRedesign()) {
                ExpandButtonLegacy(
                    modifier = Modifier.align(Alignment.CenterEnd),
                    modifier =
                        Modifier.align(Alignment.CenterEnd)
                            .sysuiResTag(
                                ColumnVolumeSlidersMotionTestKeys.TOGGLE_EXPANSION_BUTTON_TAG
                            ),
                    isExpanded = isExpanded,
                    isExpandable = isExpandable,
                    onExpandedChanged = onExpandedChanged,
@@ -132,9 +147,22 @@ fun ColumnVolumeSliders(
            exit =
                shrinkVertically(animationSpec = tween(durationMillis = COLLAPSE_DURATION_MILLIS)),
        ) {
            val isTransitionIdle by
                remember(transition) {
                    derivedStateOf {
                        transition.currentState == transition.targetState && !transition.isRunning
                    }
                }
            // This box allows sliders to slide towards top when the container is shrinking and
            // slide from top when the container is expanding.
            Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.BottomCenter) {
            Box(
                modifier =
                    Modifier.fillMaxWidth().motionTestValues {
                        isTransitionIdle exportAs
                            ColumnVolumeSlidersMotionTestKeys.isSlidersTransitionIdle
                    },
                contentAlignment = Alignment.BottomCenter,
            ) {
                Column {
                    for (index in 1..viewModels.lastIndex) {
                        val sliderViewModel: SliderViewModel = viewModels[index]
@@ -352,3 +380,10 @@ private fun topSliderPadding(isExpandable: Boolean): State<Dp> {
        label = "TopVolumeSliderPadding",
    )
}

@VisibleForTesting
object ColumnVolumeSlidersMotionTestKeys {
    const val TOGGLE_EXPANSION_BUTTON_TAG = "sliders_toggle_button"
    val isSlidersTransitionIdle: MotionTestValueKey<Boolean> =
        MotionTestValueKey("is_sliders_transition_idle")
}
+6 −5
Original line number Diff line number Diff line
@@ -13,14 +13,15 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.motion

import androidx.compose.ui.unit.Density
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import org.junit.rules.RuleChain
import platform.test.motion.MotionTestRule
import platform.test.motion.compose.ComposeToolkit
import platform.test.motion.compose.FixedConfiguration
import platform.test.motion.testing.createGoldenPathManager
import platform.test.screenshot.DeviceEmulationSpec
import platform.test.screenshot.Displays
@@ -36,14 +37,14 @@ fun createSysUiComposeMotionTestRule(
    val goldenPathManager =
        createGoldenPathManager("frameworks/base/packages/SystemUI/tests/goldens", pathConfig)
    val testScope = kosmos.testScope

    val composeScreenshotTestRule =
        ComposeScreenshotTestRule(deviceEmulationSpec, goldenPathManager)

    val fixedConfiguration =
        FixedConfiguration(density = Density(deviceEmulationSpec.display.densityDpi / 160f))
    return MotionTestRule(
        ComposeToolkit(composeScreenshotTestRule.composeRule, testScope),
        ComposeToolkit(composeScreenshotTestRule.composeRule, testScope, fixedConfiguration),
        goldenPathManager,
        bitmapDiffer = composeScreenshotTestRule,
        extraRules = RuleChain.outerRule(composeScreenshotTestRule)
        extraRules = RuleChain.outerRule(composeScreenshotTestRule),
    )
}
+6 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.android.systemui.volume.localMediaController
import com.android.systemui.volume.localPlaybackInfo
import com.android.systemui.volume.localPlaybackStateBuilder
import com.android.systemui.volume.mediaControllerRepository
import com.android.systemui.volume.mediaDeviceSessionInteractor
import com.android.systemui.volume.mediaOutputInteractor
@@ -35,6 +37,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.whenever

@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -60,6 +63,7 @@ class MediaDeviceSessionInteractorTest : SysuiTestCase() {
    fun playbackInfo_returnsPlaybackInfo() {
        with(kosmos) {
            testScope.runTest {
                whenever(localMediaController.playbackInfo).thenReturn(localPlaybackInfo)
                val session by
                    collectLastValue(mediaOutputInteractor.defaultActiveMediaSession.filterData())
                runCurrent()
@@ -75,6 +79,8 @@ class MediaDeviceSessionInteractorTest : SysuiTestCase() {
    fun playbackState_returnsPlaybackState() {
        with(kosmos) {
            testScope.runTest {
                whenever(localMediaController.playbackState)
                    .thenReturn(localPlaybackStateBuilder.build())
                val session by
                    collectLastValue(mediaOutputInteractor.defaultActiveMediaSession.filterData())
                runCurrent()
Loading