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

Commit 8ee167ec authored by Michael Mikhail's avatar Michael Mikhail Committed by Android (Google) Code Review
Browse files

Merge "[Flexiglass] hide UMO on AOD." into main

parents 849d1b8a 9e0611aa
Loading
Loading
Loading
Loading
+7 −5
Original line number Original line Diff line number Diff line
@@ -19,12 +19,11 @@ package com.android.systemui.keyguard.ui.composable.section
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.dimensionResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ContentScope
import com.android.systemui.keyguard.ui.viewmodel.KeyguardMediaViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardMediaViewModel
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.controls.ui.view.MediaHost
@@ -38,7 +37,7 @@ class MediaCarouselSection
constructor(
constructor(
    private val mediaCarouselController: MediaCarouselController,
    private val mediaCarouselController: MediaCarouselController,
    @param:Named(MediaModule.KEYGUARD) private val mediaHost: MediaHost,
    @param:Named(MediaModule.KEYGUARD) private val mediaHost: MediaHost,
    private val keyguardMediaViewModel: KeyguardMediaViewModel,
    private val keyguardMediaViewModelFactory: KeyguardMediaViewModel.Factory,
) {
) {


    @Composable
    @Composable
@@ -46,7 +45,10 @@ constructor(
        isShadeLayoutWide: Boolean,
        isShadeLayoutWide: Boolean,
        modifier: Modifier = Modifier,
        modifier: Modifier = Modifier,
    ) {
    ) {
        val isMediaVisible by keyguardMediaViewModel.isMediaVisible.collectAsStateWithLifecycle()
        val viewModel =
            rememberViewModel(traceName = "KeyguardMediaCarousel") {
                keyguardMediaViewModelFactory.create()
            }
        val horizontalPadding =
        val horizontalPadding =
            if (isShadeLayoutWide) {
            if (isShadeLayoutWide) {
                dimensionResource(id = R.dimen.notification_side_paddings)
                dimensionResource(id = R.dimen.notification_side_paddings)
@@ -55,7 +57,7 @@ constructor(
                    dimensionResource(id = R.dimen.notification_panel_margin_horizontal)
                    dimensionResource(id = R.dimen.notification_panel_margin_horizontal)
            }
            }
        MediaCarousel(
        MediaCarousel(
            isVisible = isMediaVisible,
            isVisible = viewModel.isMediaVisible,
            mediaHost = mediaHost,
            mediaHost = mediaHost,
            modifier = modifier.fillMaxWidth().padding(horizontal = horizontalPadding),
            modifier = modifier.fillMaxWidth().padding(horizontal = horizontalPadding),
            carouselController = mediaCarouselController,
            carouselController = mediaCarouselController,
+84 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 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.keyguard.ui.viewmodel

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class KeyguardMediaViewModelTest : SysuiTestCase() {
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()

    private val underTest = kosmos.keyguardMediaViewModelFactory.create()

    @Before
    fun setUp() {
        underTest.activateIn(kosmos.testScope)
    }

    @Test
    fun onDozing_noActiveMedia_mediaIsHidden() =
        kosmos.runTest {
            keyguardRepository.setIsDozing(true)

            assertThat(underTest.isMediaVisible).isFalse()
        }

    @Test
    fun onDozing_activeMediaExists_mediaIsHidden() =
        kosmos.runTest {
            val userMedia = MediaData(active = true)

            mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
            keyguardRepository.setIsDozing(true)

            assertThat(underTest.isMediaVisible).isFalse()
        }

    @Test
    fun onDeviceAwake_activeMediaExists_mediaIsVisible() =
        kosmos.runTest {
            val userMedia = MediaData(active = true)

            mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
            keyguardRepository.setIsDozing(false)

            assertThat(underTest.isMediaVisible).isTrue()
        }

    @Test
    fun onDeviceAwake_noActiveMedia_mediaIsHidden() =
        kosmos.runTest {
            keyguardRepository.setIsDozing(false)

            assertThat(underTest.isMediaVisible).isFalse()
        }
}
+44 −4
Original line number Original line Diff line number Diff line
@@ -16,10 +16,50 @@


package com.android.systemui.keyguard.ui.viewmodel
package com.android.systemui.keyguard.ui.viewmodel


import androidx.compose.runtime.getValue
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
import javax.inject.Inject
import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import kotlinx.coroutines.flow.StateFlow
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.flowOf


class KeyguardMediaViewModel @Inject constructor(mediaCarouselInteractor: MediaCarouselInteractor) {
class KeyguardMediaViewModel
    val isMediaVisible: StateFlow<Boolean> = mediaCarouselInteractor.hasActiveMediaOrRecommendation
@AssistedInject
constructor(
    mediaCarouselInteractor: MediaCarouselInteractor,
    keyguardInteractor: KeyguardInteractor,
) : ExclusiveActivatable() {

    private val hydrator = Hydrator("KeyguardMediaViewModel.hydrator")
    /**
     * Whether media carousel is visible on lockscreen. Media may be presented on lockscreen but
     * still hidden on certain surfaces like AOD
     */
    val isMediaVisible: Boolean by
        hydrator.hydratedStateOf(
            traceName = "isMediaVisible",
            source =
                keyguardInteractor.isDozing.flatMapLatestConflated { isDozing ->
                    if (isDozing) {
                        flowOf(false)
                    } else {
                        mediaCarouselInteractor.hasActiveMediaOrRecommendation
                    }
                },
            initialValue =
                !keyguardInteractor.isDozing.value &&
                    mediaCarouselInteractor.hasActiveMediaOrRecommendation.value,
        )

    override suspend fun onActivated(): Nothing {
        hydrator.activate()
    }

    @AssistedFactory
    interface Factory {
        fun create(): KeyguardMediaViewModel
    }
}
}
+30 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 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.keyguard.ui.viewmodel

import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor

val Kosmos.keyguardMediaViewModelFactory by
    Kosmos.Fixture {
        object : KeyguardMediaViewModel.Factory {
            override fun create(): KeyguardMediaViewModel {
                return KeyguardMediaViewModel(mediaCarouselInteractor, keyguardInteractor)
            }
        }
    }