Loading packages/SystemUI/compose/features/src/com/android/systemui/compose/modifiers/SysuiTestTag.kt +7 −1 Original line number Diff line number Diff line Loading @@ -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. */ Loading @@ -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 } packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt +59 −19 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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) { Loading Loading @@ -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 }, Loading @@ -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 = Loading @@ -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 Loading @@ -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 } ), ) } } Loading @@ -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") } packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt +37 −2 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -104,6 +110,11 @@ fun ColumnVolumeSliders( if (Flags.volumeRedesign()) { { ExpandButton( modifier = Modifier.sysuiResTag( ColumnVolumeSlidersMotionTestKeys .TOGGLE_EXPANSION_BUTTON_TAG ), isExpanded = isExpanded, isExpandable = isExpandable, onExpandedChanged = onExpandedChanged, Loading @@ -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, Loading @@ -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] Loading Loading @@ -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") } packages/SystemUI/multivalentTests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt +35 −2 Original line number Diff line number Diff line Loading @@ -21,13 +21,31 @@ 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.compose.createFixedConfigurationComposeMotionTestRule import platform.test.motion.testing.createGoldenPathManager import platform.test.screenshot.DeviceEmulationSpec import platform.test.screenshot.Displays import platform.test.screenshot.PathConfig import platform.test.screenshot.utils.compose.ComposeScreenshotTestRule /** Create a [MotionTestRule] for motion tests of Compose-based System UI. */ /** * Create a [MotionTestRule] for motion tests of Compose-based System UI. * * **NOTE**: This factory uses a DeviceEmulationSpec to set a fixed density at a device level. This * is known to not work reliably with Robolectric. Use * createSysUiComposeMotionTestRuleWithFixedConfig instead, where the density is overridden in * compose instead. */ @Deprecated( message = "Use createSysUiComposeMotionTestRuleWithFixedConfig() instead. This might not work with robolectric", level = DeprecationLevel.WARNING, replaceWith = ReplaceWith( "createSysUiComposeMotionTestRuleWithFixedConfig(kosmos, deviceEmulationSpec, pathConfig,)" ), ) fun createSysUiComposeMotionTestRule( kosmos: Kosmos, deviceEmulationSpec: DeviceEmulationSpec = DeviceEmulationSpec(Displays.Phone), Loading @@ -44,6 +62,21 @@ fun createSysUiComposeMotionTestRule( ComposeToolkit(composeScreenshotTestRule.composeRule, testScope), goldenPathManager, bitmapDiffer = composeScreenshotTestRule, extraRules = RuleChain.outerRule(composeScreenshotTestRule) extraRules = RuleChain.outerRule(composeScreenshotTestRule), ) } /** * Create a [MotionTestRule] with [FixedConfiguration] for motion tests of Compose-based System UI. * * **NOTE:** [FixedConfiguration] overrides the density value in compose to provide consistent UI * for testing. This affects the generation of goldens. */ fun createSysUiComposeMotionTestRuleWithFixedConfig( kosmos: Kosmos, pathConfig: PathConfig = PathConfig(), ): MotionTestRule<ComposeToolkit> { val goldenPathManager = createGoldenPathManager("frameworks/base/packages/SystemUI/tests/goldens", pathConfig) return createFixedConfigurationComposeMotionTestRule(goldenPathManager, kosmos.testScope) } packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt +6 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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) Loading @@ -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() Loading @@ -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 Loading
packages/SystemUI/compose/features/src/com/android/systemui/compose/modifiers/SysuiTestTag.kt +7 −1 Original line number Diff line number Diff line Loading @@ -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. */ Loading @@ -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 }
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt +59 −19 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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) { Loading Loading @@ -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 }, Loading @@ -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 = Loading @@ -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 Loading @@ -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 } ), ) } } Loading @@ -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") }
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt +37 −2 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -104,6 +110,11 @@ fun ColumnVolumeSliders( if (Flags.volumeRedesign()) { { ExpandButton( modifier = Modifier.sysuiResTag( ColumnVolumeSlidersMotionTestKeys .TOGGLE_EXPANSION_BUTTON_TAG ), isExpanded = isExpanded, isExpandable = isExpandable, onExpandedChanged = onExpandedChanged, Loading @@ -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, Loading @@ -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] Loading Loading @@ -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") }
packages/SystemUI/multivalentTests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt +35 −2 Original line number Diff line number Diff line Loading @@ -21,13 +21,31 @@ 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.compose.createFixedConfigurationComposeMotionTestRule import platform.test.motion.testing.createGoldenPathManager import platform.test.screenshot.DeviceEmulationSpec import platform.test.screenshot.Displays import platform.test.screenshot.PathConfig import platform.test.screenshot.utils.compose.ComposeScreenshotTestRule /** Create a [MotionTestRule] for motion tests of Compose-based System UI. */ /** * Create a [MotionTestRule] for motion tests of Compose-based System UI. * * **NOTE**: This factory uses a DeviceEmulationSpec to set a fixed density at a device level. This * is known to not work reliably with Robolectric. Use * createSysUiComposeMotionTestRuleWithFixedConfig instead, where the density is overridden in * compose instead. */ @Deprecated( message = "Use createSysUiComposeMotionTestRuleWithFixedConfig() instead. This might not work with robolectric", level = DeprecationLevel.WARNING, replaceWith = ReplaceWith( "createSysUiComposeMotionTestRuleWithFixedConfig(kosmos, deviceEmulationSpec, pathConfig,)" ), ) fun createSysUiComposeMotionTestRule( kosmos: Kosmos, deviceEmulationSpec: DeviceEmulationSpec = DeviceEmulationSpec(Displays.Phone), Loading @@ -44,6 +62,21 @@ fun createSysUiComposeMotionTestRule( ComposeToolkit(composeScreenshotTestRule.composeRule, testScope), goldenPathManager, bitmapDiffer = composeScreenshotTestRule, extraRules = RuleChain.outerRule(composeScreenshotTestRule) extraRules = RuleChain.outerRule(composeScreenshotTestRule), ) } /** * Create a [MotionTestRule] with [FixedConfiguration] for motion tests of Compose-based System UI. * * **NOTE:** [FixedConfiguration] overrides the density value in compose to provide consistent UI * for testing. This affects the generation of goldens. */ fun createSysUiComposeMotionTestRuleWithFixedConfig( kosmos: Kosmos, pathConfig: PathConfig = PathConfig(), ): MotionTestRule<ComposeToolkit> { val goldenPathManager = createGoldenPathManager("frameworks/base/packages/SystemUI/tests/goldens", pathConfig) return createFixedConfigurationComposeMotionTestRule(goldenPathManager, kosmos.testScope) }
packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt +6 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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) Loading @@ -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() Loading @@ -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