• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.statusbar.featurepods.media.domain.interactor
18 
19 import com.android.systemui.dagger.SysUISingleton
20 import com.android.systemui.dagger.qualifiers.Background
21 import com.android.systemui.media.controls.data.repository.MediaFilterRepository
22 import com.android.systemui.media.controls.shared.model.MediaData
23 import com.android.systemui.res.R
24 import com.android.systemui.scene.shared.flag.SceneContainerFlag
25 import com.android.systemui.statusbar.featurepods.media.shared.model.MediaControlChipModel
26 import javax.inject.Inject
27 import kotlinx.coroutines.CoroutineScope
28 import kotlinx.coroutines.flow.Flow
29 import kotlinx.coroutines.flow.MutableStateFlow
30 import kotlinx.coroutines.flow.SharingStarted
31 import kotlinx.coroutines.flow.StateFlow
32 import kotlinx.coroutines.flow.combine
33 import kotlinx.coroutines.flow.stateIn
34 
35 /**
36  * Interactor for managing the state of the media control chip in the status bar.
37  *
38  * Provides a [StateFlow] of [MediaControlChipModel] representing the current state of the media
39  * control chip. Emits a new [MediaControlChipModel] when there is an active media session and the
40  * corresponding user preference is found, otherwise emits null.
41  *
42  * This functionality is only enabled on large screen devices.
43  */
44 @SysUISingleton
45 class MediaControlChipInteractor
46 @Inject
47 constructor(
48     @Background private val backgroundScope: CoroutineScope,
49     mediaFilterRepository: MediaFilterRepository,
50 ) {
51     private val isEnabled = MutableStateFlow(false)
52 
53     private val mediaControlChipModelForScene: Flow<MediaControlChipModel?> =
54         combine(mediaFilterRepository.currentMedia, mediaFilterRepository.selectedUserEntries) {
55             mediaList,
56             userEntries ->
57             mediaList
58                 .mapNotNull { userEntries[it.mediaLoadedModel.instanceId] }
59                 .firstOrNull { it.active }
60                 ?.toMediaControlChipModel()
61         }
62 
63     /**
64      * A flow of [MediaControlChipModel] representing the current state of the media controls chip.
65      * This flow emits null when no active media is playing or when playback information is
66      * unavailable. This flow is only active when [SceneContainerFlag] is disabled.
67      */
68     private val mediaControlChipModelLegacy = MutableStateFlow<MediaControlChipModel?>(null)
69 
70     fun updateMediaControlChipModelLegacy(mediaData: MediaData?) {
71         if (!SceneContainerFlag.isEnabled) {
72             mediaControlChipModelLegacy.value = mediaData?.toMediaControlChipModel()
73         }
74     }
75 
76     private val _mediaControlChipModel: Flow<MediaControlChipModel?> =
77         if (SceneContainerFlag.isEnabled) {
78             mediaControlChipModelForScene
79         } else {
80             mediaControlChipModelLegacy
81         }
82 
83     /** The currently active [MediaControlChipModel] */
84     val mediaControlChipModel: StateFlow<MediaControlChipModel?> =
85         combine(_mediaControlChipModel, isEnabled) { mediaControlChipModel, isEnabled ->
86                 if (isEnabled) {
87                     mediaControlChipModel
88                 } else {
89                     null
90                 }
91             }
92             .stateIn(backgroundScope, SharingStarted.WhileSubscribed(), null)
93 
94     /**
95      * The media control chip may not be enabled on all form factors, so only the relevant form
96      * factors should initialize the interactor. This must be called from a CoreStartable.
97      */
98     fun initialize() {
99         isEnabled.value = true
100     }
101 }
102 
MediaDatanull103 private fun MediaData.toMediaControlChipModel(): MediaControlChipModel {
104     return MediaControlChipModel(
105         appIcon = this.appIcon,
106         appName = this.app,
107         songName = this.song,
108         playOrPause = this.semanticActions?.getActionById(R.id.actionPlayPause),
109     )
110 }
111