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

Commit 070f175e authored by Andre Le's avatar Andre Le
Browse files

Flexiglass: Move date and weather next to small clock if condition met

Date and weather should be either next to the small clock or below it if
the view model determine the condition met. This CL also consolate date
and weather logic into one place, removing date and weather from
smartspace since they are the same logic.

Bug: 402400952
Flag: com.android.systemui.scene_container
Test: LockscreenContentViewModelTest, manually on keyguard screen
Change-Id: I422cc3a3d183444c1c92dd965b33fe580898114b
parent af2ef928
Loading
Loading
Loading
Loading
+1 −93
Original line number Diff line number Diff line
@@ -19,24 +19,15 @@ package com.android.systemui.keyguard.ui.composable.element
import android.content.res.Resources
import android.widget.FrameLayout
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalResources
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.padding
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
@@ -86,38 +77,7 @@ constructor(
                    return@Column
                }

                val paddingBelowClockStart = dimensionResource(R.dimen.below_clock_padding_start)
                val paddingBelowClockEnd = dimensionResource(R.dimen.below_clock_padding_end)
                val paddingCardHorizontal = paddingBelowClockEnd

                if (keyguardSmartspaceViewModel.isDateWeatherDecoupled) {
                    Row(
                        verticalAlignment = Alignment.CenterVertically,
                        modifier =
                            Modifier.fillMaxWidth()
                                // All items will be constrained to be as tall as the shortest
                                // item.
                                .height(IntrinsicSize.Min)
                                .padding(start = paddingBelowClockStart),
                    ) {
                        Date(
                            modifier =
                                Modifier.burnInAware(
                                    viewModel = aodBurnInViewModel,
                                    params = burnInParams,
                                )
                        )
                        Spacer(modifier = Modifier.width(4.dp))
                        Weather(
                            modifier =
                                Modifier.burnInAware(
                                    viewModel = aodBurnInViewModel,
                                    params = burnInParams,
                                )
                        )
                    }
                }

                val paddingCardHorizontal = dimensionResource(R.dimen.below_clock_padding_end)
                Card(
                    modifier =
                        Modifier.fillMaxWidth()
@@ -153,56 +113,4 @@ constructor(
            modifier = modifier,
        )
    }

    @Composable
    private fun Weather(modifier: Modifier = Modifier) {
        val isVisible by keyguardSmartspaceViewModel.isWeatherVisible.collectAsStateWithLifecycle()
        if (!isVisible) {
            return
        }

        AndroidView(
            factory = { context ->
                FrameLayout(context).apply {
                    addView(
                        lockscreenSmartspaceController
                            .buildAndConnectWeatherView(this, false)
                            .apply {
                                layoutParams =
                                    FrameLayout.LayoutParams(
                                        FrameLayout.LayoutParams.WRAP_CONTENT,
                                        FrameLayout.LayoutParams.WRAP_CONTENT,
                                    )
                            }
                    )
                }
            },
            modifier = modifier,
        )
    }

    @Composable
    private fun Date(modifier: Modifier = Modifier) {
        val isVisible by keyguardSmartspaceViewModel.isDateVisible.collectAsStateWithLifecycle()
        if (!isVisible) {
            return
        }

        AndroidView(
            factory = { context ->
                FrameLayout(context).apply {
                    addView(
                        lockscreenSmartspaceController.buildAndConnectDateView(this, false).apply {
                            layoutParams =
                                FrameLayout.LayoutParams(
                                    FrameLayout.LayoutParams.WRAP_CONTENT,
                                    FrameLayout.LayoutParams.WRAP_CONTENT,
                                )
                        }
                    )
                }
            },
            modifier = modifier,
        )
    }
}
+19 −1
Original line number Diff line number Diff line
@@ -63,6 +63,8 @@ interface LockscreenLayoutViewModel {
     * This value is meaningless if [isDynamicClockEnabled] is `false`.
     */
    val isDateAndWeatherVisibleWithLargeClock: Boolean
    /** Whether date and weather should currently be visible. */
    val isDateAndWeatherVisible: Boolean
    /** Whether smart space should currently be showing. */
    val isSmartSpaceVisible: Boolean
    /** Whether media should currently be showing. */
@@ -76,6 +78,11 @@ interface LockscreenLayoutViewModel {
    val isUdfpsSupported: Boolean
    /** Amount of horizontal translation that should be applied to elements in the scene. */
    val unfoldTranslations: UnfoldTranslations
    /**
     * Whether date and weather should be below the small clock. If `false`, the date and weather
     * should be next to the small clock.
     */
    val shouldDateWeatherBeBelowSmallClock: Boolean
}

@Immutable
@@ -189,6 +196,8 @@ fun LockscreenSceneLayout(
            ContentColumn(
                isSmallClockVisible = layout.isSmallClockVisible,
                smallClock = smallClock,
                isDateAndWeatherVisible = viewModel.isDateAndWeatherVisible,
                shouldDateWeatherBeBelowSmallClock = viewModel.shouldDateWeatherBeBelowSmallClock,
                dateAndWeather = dateAndWeather,
                isSmartSpaceVisible = viewModel.isSmartSpaceVisible,
                smartSpace = smartSpace,
@@ -497,6 +506,8 @@ private fun ShortcutArea(
private fun ContentColumn(
    isSmallClockVisible: Boolean,
    smallClock: @Composable () -> Unit,
    isDateAndWeatherVisible: Boolean,
    shouldDateWeatherBeBelowSmallClock: Boolean,
    dateAndWeather: @Composable (Orientation) -> Unit,
    isSmartSpaceVisible: Boolean,
    smartSpace: @Composable () -> Unit,
@@ -514,9 +525,16 @@ private fun ContentColumn(
                modifier = Modifier.padding(bottom = 24.dp),
            ) {
                smallClock()

                if (isDateAndWeatherVisible && !shouldDateWeatherBeBelowSmallClock) {
                    dateAndWeather(Orientation.Vertical)
                }
            }
        }

        if (isDateAndWeatherVisible && shouldDateWeatherBeBelowSmallClock) {
            dateAndWeather(Orientation.Horizontal)
        }

        AnimatedVisibility(isSmartSpaceVisible) {
            Box(Modifier.padding(bottom = 24.dp)) { smartSpace() }
+77 −0
Original line number Diff line number Diff line
@@ -21,15 +21,19 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.authController
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.deviceentry.domain.interactor.deviceEntryBypassInteractor
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
import com.android.systemui.keyguard.domain.interactor.keyguardBlueprintInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.transition.fakeKeyguardTransitionAnimationCallback
import com.android.systemui.keyguard.shared.transition.keyguardTransitionAnimationCallback
import com.android.systemui.keyguard.shared.transition.keyguardTransitionAnimationCallbackDelegator
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
@@ -51,12 +55,15 @@ import com.android.systemui.statusbar.notification.data.repository.ActiveNotific
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.testKosmos
import com.android.systemui.unfold.domain.interactor.unfoldTransitionInteractor
import com.android.systemui.unfold.fakeUnfoldTransitionProgressProvider
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.wallpapers.domain.interactor.wallpaperFocalAreaInteractor
import com.google.common.truth.Truth.assertThat
import java.util.Locale
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -126,6 +133,52 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
            assertThat(underTest.layout.isNotificationsVisible).isFalse()
        }

    @Test
    fun isDateAndWeatherVisible_isDateWeatherDecoupledFalse_false() =
        kosmos.runTest {
            val smartspaceViewModel = mock<KeyguardSmartspaceViewModel>()
            whenever(smartspaceViewModel.isDateWeatherDecoupled).thenReturn(false)

            val underTest = createTestViewModel(smartspaceViewModel = smartspaceViewModel)

            assertThat(underTest.layout.isDateAndWeatherVisible).isFalse()
        }

    @Test
    fun isDateAndWeatherVisible_isDateWeatherDecoupledTrue_true() =
        kosmos.runTest {
            val smartspaceViewModel = mock<KeyguardSmartspaceViewModel>()
            whenever(smartspaceViewModel.isDateWeatherDecoupled).thenReturn(true)

            val underTest = createTestViewModel(smartspaceViewModel = smartspaceViewModel)

            assertThat(underTest.layout.isDateAndWeatherVisible).isTrue()
        }

    @Test
    fun shouldDateWeatherBeBelowSmallClock_false() =
        kosmos.runTest {
            val clockViewModel = mock<KeyguardClockViewModel>()
            whenever(clockViewModel.shouldDateWeatherBeBelowSmallClock)
                .thenReturn(MutableStateFlow(false))

            val underTest = createTestViewModel(clockViewModel = clockViewModel)

            assertThat(underTest.layout.shouldDateWeatherBeBelowSmallClock).isFalse()
        }

    @Test
    fun shouldDateWeatherBeBelowSmallClock_true() =
        kosmos.runTest {
            val clockViewModel = mock<KeyguardClockViewModel>()
            whenever(clockViewModel.shouldDateWeatherBeBelowSmallClock)
                .thenReturn(MutableStateFlow(true))

            val underTest = createTestViewModel(clockViewModel = clockViewModel)

            assertThat(underTest.layout.shouldDateWeatherBeBelowSmallClock).isTrue()
        }

    @Test
    fun unfoldTranslations() =
        kosmos.runTest {
@@ -285,4 +338,28 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
        )
        return maxTranslation
    }

    private fun Kosmos.createTestViewModel(
        smartspaceViewModel: KeyguardSmartspaceViewModel = keyguardSmartspaceViewModel,
        clockViewModel: KeyguardClockViewModel = keyguardClockViewModel,
    ): LockscreenContentViewModel {
        return LockscreenContentViewModel(
            clockInteractor = keyguardClockInteractor,
            interactor = keyguardBlueprintInteractor,
            authController = authController,
            touchHandlingFactory = keyguardTouchHandlingViewModelFactory,
            shadeModeInteractor = shadeModeInteractor,
            unfoldTransitionInteractor = unfoldTransitionInteractor,
            deviceEntryBypassInteractor = deviceEntryBypassInteractor,
            transitionInteractor = keyguardTransitionInteractor,
            keyguardTransitionAnimationCallbackDelegator =
                keyguardTransitionAnimationCallbackDelegator,
            keyguardTransitionAnimationCallback = keyguardTransitionAnimationCallback,
            keyguardMediaViewModelFactory = keyguardMediaViewModelFactory,
            keyguardSmartspaceViewModel = smartspaceViewModel,
            keyguardClockViewModel = clockViewModel,
            activeNotificationsInteractor = activeNotificationsInteractor,
            wallpaperFocalAreaInteractor = wallpaperFocalAreaInteractor,
        )
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ constructor(
        KeyguardTransitionAnimationCallbackDelegator,
    keyguardMediaViewModelFactory: KeyguardMediaViewModel.Factory,
    keyguardSmartspaceViewModel: KeyguardSmartspaceViewModel,
    keyguardClockViewModel: KeyguardClockViewModel,
    activeNotificationsInteractor: ActiveNotificationsInteractor,
    @Assisted private val keyguardTransitionAnimationCallback: KeyguardTransitionAnimationCallback,
    private val wallpaperFocalAreaInteractor: WallpaperFocalAreaInteractor,
@@ -130,6 +131,9 @@ constructor(
                        clockInteractor.currentClock.value.isDateAndWeatherVisibleWithLargeClock(),
                )

            override val isDateAndWeatherVisible: Boolean =
                keyguardSmartspaceViewModel.isDateWeatherDecoupled

            private fun ClockController?.isDateAndWeatherVisibleWithLargeClock(): Boolean {
                return this?.largeClock?.config?.hasCustomWeatherDataDisplay == false
            }
@@ -167,6 +171,13 @@ constructor(
                                unfoldTransitionInteractor.unfoldTranslationX(isOnStartSide = false),
                        )
                }

            override val shouldDateWeatherBeBelowSmallClock: Boolean by
                hydrator.hydratedStateOf(
                    traceName = "shouldDateWeatherBeBelowSmallClock",
                    source = keyguardClockViewModel.shouldDateWeatherBeBelowSmallClock,
                    initialValue = keyguardClockViewModel.shouldDateWeatherBeBelowSmallClock.value,
                )
        }

    override suspend fun onActivated(): Nothing {
+1 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ val Kosmos.lockscreenContentViewModelFactory by Fixture {
                    keyguardTransitionAnimationCallbackDelegator,
                keyguardMediaViewModelFactory = keyguardMediaViewModelFactory,
                keyguardSmartspaceViewModel = keyguardSmartspaceViewModel,
                keyguardClockViewModel = keyguardClockViewModel,
                activeNotificationsInteractor = activeNotificationsInteractor,
                keyguardTransitionAnimationCallback = keyguardTransitionAnimationCallback,
                wallpaperFocalAreaInteractor = wallpaperFocalAreaInteractor,