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

Commit a45f2e7b authored by William Xiao's avatar William Xiao
Browse files

Show the UMO in the hub mode UI

When media is playing or recommendations are present, the UMO will be
shown on top of the grid. It's not integrated into the layout grid
yet as that will be refactored soon.

Bug: 308638964
Bug: 304584416
Flag: ACONFIG com.android.systemui.communal_hub DEVELOPMENT
Test: atest CommunalMediaRepositoryImplTest CommunalInteractorTest MediaHierarchyManagerTest
Change-Id: Id50e313d64f313ea5ecbfb0bedb39fef9a50b449
parent b22ed81f
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -3,12 +3,15 @@ package com.android.systemui.communal.ui.compose
import android.appwidget.AppWidgetHostView
import android.os.Bundle
import android.util.SizeF
import android.widget.FrameLayout
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
@@ -25,6 +28,8 @@ import androidx.compose.ui.viewinterop.AndroidView
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.ui.model.CommunalContentUiModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.media.controls.ui.MediaHierarchyManager
import com.android.systemui.media.controls.ui.MediaHostState

@Composable
fun CommunalHub(
@@ -33,6 +38,7 @@ fun CommunalHub(
) {
    val showTutorial by viewModel.showTutorialContent.collectAsState(initial = false)
    val widgetContent by viewModel.widgetContent.collectAsState(initial = emptyList())
    val isMediaPlaying by viewModel.isMediaPlaying.collectAsState(initial = false)
    Box(
        modifier = modifier.fillMaxSize().background(Color.White),
    ) {
@@ -68,6 +74,33 @@ fun CommunalHub(
                }
            }
        }

        if (isMediaPlaying) {
            Box(
                modifier =
                    Modifier.width(Dimensions.CardWidth)
                        .height(Dimensions.CardHeightThird)
                        .padding(Dimensions.Spacing)
            ) {
                AndroidView(
                    modifier = Modifier.fillMaxSize(),
                    factory = {
                        viewModel.mediaHost.expansion = MediaHostState.EXPANDED
                        viewModel.mediaHost.showsOnlyActiveMedia = false
                        viewModel.mediaHost.falsingProtectionNeeded = false
                        viewModel.mediaHost.init(MediaHierarchyManager.LOCATION_COMMUNAL_HUB)
                        viewModel.mediaHost.hostView.layoutParams =
                            FrameLayout.LayoutParams(
                                FrameLayout.LayoutParams.MATCH_PARENT,
                                FrameLayout.LayoutParams.MATCH_PARENT
                            )
                        viewModel.mediaHost.hostView
                    },
                    // For reusing composition in lazy lists.
                    onReset = {},
                )
            }
        }
    }
}

+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.communal.dagger

import com.android.systemui.communal.data.repository.CommunalMediaRepositoryModule
import com.android.systemui.communal.data.repository.CommunalRepositoryModule
import com.android.systemui.communal.data.repository.CommunalTutorialRepositoryModule
import com.android.systemui.communal.data.repository.CommunalWidgetRepositoryModule
@@ -24,6 +25,7 @@ import dagger.Module
@Module(
    includes =
        [
            CommunalMediaRepositoryModule::class,
            CommunalRepositoryModule::class,
            CommunalTutorialRepositoryModule::class,
            CommunalWidgetRepositoryModule::class,
+73 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.communal.data.repository

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.pipeline.MediaDataManager
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart

/** Encapsulates the state of smartspace in communal. */
interface CommunalMediaRepository {
    val mediaPlaying: Flow<Boolean>
}

@SysUISingleton
class CommunalMediaRepositoryImpl
@Inject
constructor(
    private val mediaDataManager: MediaDataManager,
) : CommunalMediaRepository {

    private val mediaDataListener =
        object : MediaDataManager.Listener {
            override fun onMediaDataLoaded(
                key: String,
                oldKey: String?,
                data: MediaData,
                immediately: Boolean,
                receivedSmartspaceCardLatency: Int,
                isSsReactivated: Boolean
            ) {
                if (!mediaDataManager.hasAnyMediaOrRecommendation()) {
                    return
                }
                _mediaPlaying.value = true
            }

            override fun onMediaDataRemoved(key: String) {
                if (mediaDataManager.hasAnyMediaOrRecommendation()) {
                    return
                }
                _mediaPlaying.value = false
            }
        }

    private val _mediaPlaying: MutableStateFlow<Boolean> = MutableStateFlow(false)

    override val mediaPlaying: Flow<Boolean> =
        _mediaPlaying
            .onStart {
                mediaDataManager.addListener(mediaDataListener)
                _mediaPlaying.value = mediaDataManager.hasAnyMediaOrRecommendation()
            }
            .onCompletion { mediaDataManager.removeListener(mediaDataListener) }
}
+25 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.communal.data.repository

import dagger.Binds
import dagger.Module

@Module
interface CommunalMediaRepositoryModule {
    @Binds fun communalMediaRepository(impl: CommunalMediaRepositoryImpl): CommunalMediaRepository
}
+5 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.communal.domain.interactor

import com.android.systemui.communal.data.repository.CommunalMediaRepository
import com.android.systemui.communal.data.repository.CommunalRepository
import com.android.systemui.communal.data.repository.CommunalWidgetRepository
import com.android.systemui.communal.shared.model.CommunalAppWidgetInfo
@@ -34,6 +35,7 @@ class CommunalInteractor
constructor(
    private val communalRepository: CommunalRepository,
    widgetRepository: CommunalWidgetRepository,
    mediaRepository: CommunalMediaRepository,
) {

    /** Whether communal features are enabled. */
@@ -51,6 +53,9 @@ constructor(
     */
    val widgetContent: Flow<List<CommunalWidgetContentModel>> = widgetRepository.communalWidgets

    /** A flow indicating whether or not media is playing. */
    val mediaPlaying: Flow<Boolean> = mediaRepository.mediaPlaying

    /**
     * Target scene as requested by the underlying [SceneTransitionLayout] or through
     * [onSceneChanged].
Loading