Loading packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt +7 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,13 @@ val SceneContainerTransitions = transitions { goneToShadeTransition(durationScale = 0.9) } from(Scenes.Gone, to = Scenes.QuickSettings) { goneToQuickSettingsTransition() } from( Scenes.Gone, to = Scenes.QuickSettings, key = SlightlyFasterShadeCollapse, ) { goneToQuickSettingsTransition(durationScale = 0.9) } from(Scenes.Gone, to = Scenes.QuickSettingsShade) { goneToQuickSettingsShadeTransition() } from(Scenes.Lockscreen, to = Scenes.Bouncer) { lockscreenToBouncerTransition() } from(Scenes.Lockscreen, to = Scenes.Communal) { lockscreenToCommunalTransition() } Loading packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt +46 −15 Original line number Diff line number Diff line Loading @@ -19,7 +19,10 @@ package com.android.systemui.shade.ui.composable import android.view.ContextThemeWrapper import android.view.ViewGroup import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsHoveredAsState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column Loading @@ -32,7 +35,9 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ColorScheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf Loading @@ -40,6 +45,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.graphics.graphicsLayer Loading @@ -58,6 +64,7 @@ import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.TransitionState import com.android.compose.animation.scene.ValueKey import com.android.compose.animation.scene.animateElementFloatAsState import com.android.compose.modifiers.thenIf import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.settingslib.Utils import com.android.systemui.battery.BatteryMeterView Loading @@ -69,6 +76,7 @@ import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.privacy.OngoingPrivacyChip import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.onScrimDim import com.android.systemui.shade.ui.composable.ShadeHeader.Dimensions.CollapsedHeight import com.android.systemui.shade.ui.composable.ShadeHeader.Values.ClockScale import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel Loading @@ -79,7 +87,6 @@ import com.android.systemui.statusbar.phone.ui.TintedIconManager import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel import com.android.systemui.statusbar.policy.Clock import kotlin.math.max object ShadeHeader { object Elements { Loading @@ -103,6 +110,8 @@ object ShadeHeader { object Colors { val ColorScheme.shadeHeaderText: Color get() = Color.White val ColorScheme.onScrimDim: Color get() = Color.DarkGray } object TestTags { Loading Loading @@ -130,7 +139,7 @@ fun SceneScope.CollapsedShadeHeader( val horizontalPadding = max(LocalScreenCornerRadius.current / 2f, Shade.Dimensions.HorizontalPadding) val useExpandedFormat by val useExpandedTextFormat by remember(cutoutLocation) { derivedStateOf { cutoutLocation != CutoutLocation.CENTER || Loading @@ -138,6 +147,10 @@ fun SceneScope.CollapsedShadeHeader( } } val isLargeScreenLayout = LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Medium || LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Expanded val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle() // This layout assumes it is globally positioned at (0, 0) and is the Loading Loading @@ -182,22 +195,22 @@ fun SceneScope.CollapsedShadeHeader( Modifier.element(ShadeHeader.Elements.CollapsedContentEnd) .padding(horizontal = horizontalPadding) ) { SystemIconContainer( modifier = Modifier.align(Alignment.CenterVertically) ) { when (LocalWindowSizeClass.current.widthSizeClass) { WindowWidthSizeClass.Medium, WindowWidthSizeClass.Expanded -> if (isLargeScreenLayout) { ShadeCarrierGroup( viewModel = viewModel, modifier = Modifier.align(Alignment.CenterVertically), ) } SystemIconContainer( viewModel = viewModel, isClickable = isLargeScreenLayout, modifier = Modifier.align(Alignment.CenterVertically) ) { StatusIcons( viewModel = viewModel, createTintedIconManager = createTintedIconManager, statusBarIconController = statusBarIconController, useExpandedFormat = useExpandedFormat, useExpandedFormat = useExpandedTextFormat, modifier = Modifier.align(Alignment.CenterVertically) .padding(end = 6.dp) Loading @@ -206,7 +219,7 @@ fun SceneScope.CollapsedShadeHeader( BatteryIcon( createBatteryMeterViewController = createBatteryMeterViewController, useExpandedFormat = useExpandedFormat, useExpandedFormat = useExpandedTextFormat, modifier = Modifier.align(Alignment.CenterVertically), ) } Loading Loading @@ -322,7 +335,7 @@ fun SceneScope.ExpandedShadeHeader( modifier = Modifier.widthIn(max = 90.dp).align(Alignment.CenterVertically), ) Spacer(modifier = Modifier.weight(1f)) SystemIconContainer { SystemIconContainer(viewModel = viewModel, isClickable = false) { StatusIcons( viewModel = viewModel, createTintedIconManager = createTintedIconManager, Loading Loading @@ -531,12 +544,30 @@ private fun SceneScope.StatusIcons( @Composable private fun SystemIconContainer( viewModel: ShadeHeaderViewModel, isClickable: Boolean, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { // TODO(b/298524053): add hover state for this container val interactionSource = remember { MutableInteractionSource() } val isHovered by interactionSource.collectIsHoveredAsState() val hoverModifier = Modifier .clip(RoundedCornerShape(CollapsedHeight / 4)) .background(MaterialTheme.colorScheme.onScrimDim) Row( modifier = modifier.height(CollapsedHeight), modifier = modifier .height(CollapsedHeight) .padding(vertical = CollapsedHeight / 4) .thenIf(isClickable) { Modifier.clickable( interactionSource = interactionSource, indication = null, onClick = { viewModel.onSystemIconContainerClicked() }, ) } .thenIf(isHovered) { hoverModifier }, content = content, ) } Loading packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt +66 −0 Original line number Diff line number Diff line Loading @@ -6,15 +6,27 @@ import android.provider.Settings import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState import com.android.compose.animation.scene.SceneKey import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.activityStarter import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.fakeMobileIconsInteractor import com.android.systemui.testKosmos import com.android.systemui.util.mockito.argThat import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test Loading @@ -24,12 +36,16 @@ import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) @EnableSceneContainer class ShadeHeaderViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val mobileIconsInteractor = kosmos.fakeMobileIconsInteractor private val sceneInteractor = kosmos.sceneInteractor private val deviceEntryInteractor = kosmos.deviceEntryInteractor private val underTest: ShadeHeaderViewModel = kosmos.shadeHeaderViewModel Loading Loading @@ -77,6 +93,30 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { ) } @Test fun onSystemIconContainerClicked_locked_collapsesShadeToLockscreen() = testScope.runTest { setDeviceEntered(false) setScene(Scenes.Shade) underTest.onSystemIconContainerClicked() runCurrent() assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Lockscreen) } @Test fun onSystemIconContainerClicked_unlocked_collapsesShadeToGone() = testScope.runTest { setDeviceEntered(true) setScene(Scenes.Shade) underTest.onSystemIconContainerClicked() runCurrent() assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Gone) } companion object { private val SUB_1 = SubscriptionModel( Loading @@ -93,6 +133,32 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { profileClass = PROFILE_CLASS_UNSET, ) } private fun setScene(key: SceneKey) { sceneInteractor.changeScene(key, "test") sceneInteractor.setTransitionState( MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key)) ) testScope.runCurrent() } private fun TestScope.setDeviceEntered(isEntered: Boolean) { if (isEntered) { // Unlock the device marking the device has entered. kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) runCurrent() } setScene( if (isEntered) { Scenes.Gone } else { Scenes.Lockscreen } ) assertThat(deviceEntryInteractor.isDeviceEntered.value).isEqualTo(isEntered) } } private class IntentMatcherAction(private val action: String) : ArgumentMatcher<Intent> { Loading packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt +13 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,9 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.privacy.OngoingPrivacyChip import com.android.systemui.privacy.PrivacyItem import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.TransitionKeys import com.android.systemui.shade.domain.interactor.PrivacyChipInteractor import com.android.systemui.shade.domain.interactor.ShadeHeaderClockInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor Loading Loading @@ -57,6 +60,7 @@ constructor( @Application private val applicationScope: CoroutineScope, context: Context, private val activityStarter: ActivityStarter, private val sceneInteractor: SceneInteractor, shadeInteractor: ShadeInteractor, mobileIconsInteractor: MobileIconsInteractor, val mobileIconsViewModel: MobileIconsViewModel, Loading Loading @@ -139,6 +143,15 @@ constructor( clockInteractor.launchClockActivity() } /** Notifies that the system icons container was clicked. */ fun onSystemIconContainerClicked() { sceneInteractor.changeScene( SceneFamilies.Home, "ShadeHeaderViewModel.onSystemIconContainerClicked", TransitionKeys.SlightlyFasterShadeCollapse, ) } /** Notifies that the shadeCarrierGroup was clicked. */ fun onShadeCarrierGroupClicked() { activityStarter.postStartActivityDismissingKeyguard( Loading packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt +2 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import com.android.systemui.broadcast.broadcastDispatcher import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.plugins.activityStarter import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.shade.domain.interactor.privacyChipInteractor import com.android.systemui.shade.domain.interactor.shadeHeaderClockInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor Loading @@ -33,6 +34,7 @@ val Kosmos.shadeHeaderViewModel: ShadeHeaderViewModel by applicationScope = applicationCoroutineScope, context = applicationContext, activityStarter = activityStarter, sceneInteractor = sceneInteractor, shadeInteractor = shadeInteractor, mobileIconsInteractor = mobileIconsInteractor, mobileIconsViewModel = mobileIconsViewModel, Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt +7 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,13 @@ val SceneContainerTransitions = transitions { goneToShadeTransition(durationScale = 0.9) } from(Scenes.Gone, to = Scenes.QuickSettings) { goneToQuickSettingsTransition() } from( Scenes.Gone, to = Scenes.QuickSettings, key = SlightlyFasterShadeCollapse, ) { goneToQuickSettingsTransition(durationScale = 0.9) } from(Scenes.Gone, to = Scenes.QuickSettingsShade) { goneToQuickSettingsShadeTransition() } from(Scenes.Lockscreen, to = Scenes.Bouncer) { lockscreenToBouncerTransition() } from(Scenes.Lockscreen, to = Scenes.Communal) { lockscreenToCommunalTransition() } Loading
packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt +46 −15 Original line number Diff line number Diff line Loading @@ -19,7 +19,10 @@ package com.android.systemui.shade.ui.composable import android.view.ContextThemeWrapper import android.view.ViewGroup import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsHoveredAsState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column Loading @@ -32,7 +35,9 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ColorScheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf Loading @@ -40,6 +45,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.graphics.graphicsLayer Loading @@ -58,6 +64,7 @@ import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.TransitionState import com.android.compose.animation.scene.ValueKey import com.android.compose.animation.scene.animateElementFloatAsState import com.android.compose.modifiers.thenIf import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.settingslib.Utils import com.android.systemui.battery.BatteryMeterView Loading @@ -69,6 +76,7 @@ import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.privacy.OngoingPrivacyChip import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.onScrimDim import com.android.systemui.shade.ui.composable.ShadeHeader.Dimensions.CollapsedHeight import com.android.systemui.shade.ui.composable.ShadeHeader.Values.ClockScale import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel Loading @@ -79,7 +87,6 @@ import com.android.systemui.statusbar.phone.ui.TintedIconManager import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel import com.android.systemui.statusbar.policy.Clock import kotlin.math.max object ShadeHeader { object Elements { Loading @@ -103,6 +110,8 @@ object ShadeHeader { object Colors { val ColorScheme.shadeHeaderText: Color get() = Color.White val ColorScheme.onScrimDim: Color get() = Color.DarkGray } object TestTags { Loading Loading @@ -130,7 +139,7 @@ fun SceneScope.CollapsedShadeHeader( val horizontalPadding = max(LocalScreenCornerRadius.current / 2f, Shade.Dimensions.HorizontalPadding) val useExpandedFormat by val useExpandedTextFormat by remember(cutoutLocation) { derivedStateOf { cutoutLocation != CutoutLocation.CENTER || Loading @@ -138,6 +147,10 @@ fun SceneScope.CollapsedShadeHeader( } } val isLargeScreenLayout = LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Medium || LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Expanded val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle() // This layout assumes it is globally positioned at (0, 0) and is the Loading Loading @@ -182,22 +195,22 @@ fun SceneScope.CollapsedShadeHeader( Modifier.element(ShadeHeader.Elements.CollapsedContentEnd) .padding(horizontal = horizontalPadding) ) { SystemIconContainer( modifier = Modifier.align(Alignment.CenterVertically) ) { when (LocalWindowSizeClass.current.widthSizeClass) { WindowWidthSizeClass.Medium, WindowWidthSizeClass.Expanded -> if (isLargeScreenLayout) { ShadeCarrierGroup( viewModel = viewModel, modifier = Modifier.align(Alignment.CenterVertically), ) } SystemIconContainer( viewModel = viewModel, isClickable = isLargeScreenLayout, modifier = Modifier.align(Alignment.CenterVertically) ) { StatusIcons( viewModel = viewModel, createTintedIconManager = createTintedIconManager, statusBarIconController = statusBarIconController, useExpandedFormat = useExpandedFormat, useExpandedFormat = useExpandedTextFormat, modifier = Modifier.align(Alignment.CenterVertically) .padding(end = 6.dp) Loading @@ -206,7 +219,7 @@ fun SceneScope.CollapsedShadeHeader( BatteryIcon( createBatteryMeterViewController = createBatteryMeterViewController, useExpandedFormat = useExpandedFormat, useExpandedFormat = useExpandedTextFormat, modifier = Modifier.align(Alignment.CenterVertically), ) } Loading Loading @@ -322,7 +335,7 @@ fun SceneScope.ExpandedShadeHeader( modifier = Modifier.widthIn(max = 90.dp).align(Alignment.CenterVertically), ) Spacer(modifier = Modifier.weight(1f)) SystemIconContainer { SystemIconContainer(viewModel = viewModel, isClickable = false) { StatusIcons( viewModel = viewModel, createTintedIconManager = createTintedIconManager, Loading Loading @@ -531,12 +544,30 @@ private fun SceneScope.StatusIcons( @Composable private fun SystemIconContainer( viewModel: ShadeHeaderViewModel, isClickable: Boolean, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { // TODO(b/298524053): add hover state for this container val interactionSource = remember { MutableInteractionSource() } val isHovered by interactionSource.collectIsHoveredAsState() val hoverModifier = Modifier .clip(RoundedCornerShape(CollapsedHeight / 4)) .background(MaterialTheme.colorScheme.onScrimDim) Row( modifier = modifier.height(CollapsedHeight), modifier = modifier .height(CollapsedHeight) .padding(vertical = CollapsedHeight / 4) .thenIf(isClickable) { Modifier.clickable( interactionSource = interactionSource, indication = null, onClick = { viewModel.onSystemIconContainerClicked() }, ) } .thenIf(isHovered) { hoverModifier }, content = content, ) } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt +66 −0 Original line number Diff line number Diff line Loading @@ -6,15 +6,27 @@ import android.provider.Settings import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState import com.android.compose.animation.scene.SceneKey import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.activityStarter import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.fakeMobileIconsInteractor import com.android.systemui.testKosmos import com.android.systemui.util.mockito.argThat import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test Loading @@ -24,12 +36,16 @@ import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) @EnableSceneContainer class ShadeHeaderViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val mobileIconsInteractor = kosmos.fakeMobileIconsInteractor private val sceneInteractor = kosmos.sceneInteractor private val deviceEntryInteractor = kosmos.deviceEntryInteractor private val underTest: ShadeHeaderViewModel = kosmos.shadeHeaderViewModel Loading Loading @@ -77,6 +93,30 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { ) } @Test fun onSystemIconContainerClicked_locked_collapsesShadeToLockscreen() = testScope.runTest { setDeviceEntered(false) setScene(Scenes.Shade) underTest.onSystemIconContainerClicked() runCurrent() assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Lockscreen) } @Test fun onSystemIconContainerClicked_unlocked_collapsesShadeToGone() = testScope.runTest { setDeviceEntered(true) setScene(Scenes.Shade) underTest.onSystemIconContainerClicked() runCurrent() assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Gone) } companion object { private val SUB_1 = SubscriptionModel( Loading @@ -93,6 +133,32 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { profileClass = PROFILE_CLASS_UNSET, ) } private fun setScene(key: SceneKey) { sceneInteractor.changeScene(key, "test") sceneInteractor.setTransitionState( MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key)) ) testScope.runCurrent() } private fun TestScope.setDeviceEntered(isEntered: Boolean) { if (isEntered) { // Unlock the device marking the device has entered. kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) runCurrent() } setScene( if (isEntered) { Scenes.Gone } else { Scenes.Lockscreen } ) assertThat(deviceEntryInteractor.isDeviceEntered.value).isEqualTo(isEntered) } } private class IntentMatcherAction(private val action: String) : ArgumentMatcher<Intent> { Loading
packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt +13 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,9 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.privacy.OngoingPrivacyChip import com.android.systemui.privacy.PrivacyItem import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.TransitionKeys import com.android.systemui.shade.domain.interactor.PrivacyChipInteractor import com.android.systemui.shade.domain.interactor.ShadeHeaderClockInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor Loading Loading @@ -57,6 +60,7 @@ constructor( @Application private val applicationScope: CoroutineScope, context: Context, private val activityStarter: ActivityStarter, private val sceneInteractor: SceneInteractor, shadeInteractor: ShadeInteractor, mobileIconsInteractor: MobileIconsInteractor, val mobileIconsViewModel: MobileIconsViewModel, Loading Loading @@ -139,6 +143,15 @@ constructor( clockInteractor.launchClockActivity() } /** Notifies that the system icons container was clicked. */ fun onSystemIconContainerClicked() { sceneInteractor.changeScene( SceneFamilies.Home, "ShadeHeaderViewModel.onSystemIconContainerClicked", TransitionKeys.SlightlyFasterShadeCollapse, ) } /** Notifies that the shadeCarrierGroup was clicked. */ fun onShadeCarrierGroupClicked() { activityStarter.postStartActivityDismissingKeyguard( Loading
packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt +2 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import com.android.systemui.broadcast.broadcastDispatcher import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.plugins.activityStarter import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.shade.domain.interactor.privacyChipInteractor import com.android.systemui.shade.domain.interactor.shadeHeaderClockInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor Loading @@ -33,6 +34,7 @@ val Kosmos.shadeHeaderViewModel: ShadeHeaderViewModel by applicationScope = applicationCoroutineScope, context = applicationContext, activityStarter = activityStarter, sceneInteractor = sceneInteractor, shadeInteractor = shadeInteractor, mobileIconsInteractor = mobileIconsInteractor, mobileIconsViewModel = mobileIconsViewModel, Loading