• 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.dreams.homecontrols.system.domain.interactor
18 
19 import android.content.ComponentName
20 import com.android.systemui.controls.ControlsServiceInfo
21 import com.android.systemui.controls.dagger.ControlsComponent
22 import com.android.systemui.controls.management.ControlsListingController
23 import com.android.systemui.controls.panels.AuthorizedPanelsRepository
24 import com.android.systemui.controls.panels.SelectedComponentRepository
25 import com.android.systemui.dagger.SysUISingleton
26 import com.android.systemui.dagger.qualifiers.Background
27 import com.android.systemui.user.data.repository.UserRepository
28 import com.android.systemui.util.kotlin.getOrNull
29 import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
30 import javax.inject.Inject
31 import kotlinx.coroutines.CoroutineScope
32 import kotlinx.coroutines.channels.awaitClose
33 import kotlinx.coroutines.flow.Flow
34 import kotlinx.coroutines.flow.SharingStarted
35 import kotlinx.coroutines.flow.StateFlow
36 import kotlinx.coroutines.flow.combine
37 import kotlinx.coroutines.flow.emptyFlow
38 import kotlinx.coroutines.flow.flatMapLatest
39 import kotlinx.coroutines.flow.map
40 import kotlinx.coroutines.flow.onStart
41 import kotlinx.coroutines.flow.stateIn
42 
43 @SysUISingleton
44 class HomeControlsComponentInteractor
45 @Inject
46 constructor(
47     private val selectedComponentRepository: SelectedComponentRepository,
48     controlsComponent: ControlsComponent,
49     authorizedPanelsRepository: AuthorizedPanelsRepository,
50     userRepository: UserRepository,
51     @Background private val bgScope: CoroutineScope,
52 ) {
53     private val controlsListingController: ControlsListingController? =
54         controlsComponent.getControlsListingController().getOrNull()
55 
56     /** Gets the current user's selected panel, or null if there isn't one */
57     private val selectedPanel: Flow<SelectedComponentRepository.SelectedComponent?> =
58         userRepository.selectedUserInfo
59             .flatMapLatest { user ->
60                 selectedComponentRepository.selectedComponentFlow(user.userHandle)
61             }
62             .map { if (it?.isPanel == true) it else null }
63 
64     /** Gets the current user's authorized panels */
65     private val allAuthorizedPanels: Flow<Set<String>> =
66         userRepository.selectedUserInfo.flatMapLatest { user ->
67             authorizedPanelsRepository.observeAuthorizedPanels(user.userHandle)
68         }
69 
70     /** Gets all the available services from [ControlsListingController] */
71     private fun allAvailableServices(): Flow<List<ControlsServiceInfo>> {
72         if (controlsListingController == null) {
73             return emptyFlow()
74         }
75         return conflatedCallbackFlow {
76                 val listener =
77                     object : ControlsListingController.ControlsListingCallback {
78                         override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
79                             trySend(serviceInfos)
80                         }
81                     }
82                 controlsListingController.addCallback(listener)
83                 awaitClose { controlsListingController.removeCallback(listener) }
84             }
85             .onStart { emit(controlsListingController.getCurrentServices()) }
86     }
87 
88     /** Gets all panels which are available and authorized by the user */
89     private val allAvailableAndAuthorizedPanels: Flow<List<PanelComponent>> =
90         combine(allAvailableServices(), allAuthorizedPanels) { serviceInfos, authorizedPanels ->
91             serviceInfos.mapNotNull {
92                 val panelActivity = it.panelActivity
93                 if (it.componentName.packageName in authorizedPanels && panelActivity != null) {
94                     PanelComponent(it.componentName, panelActivity)
95                 } else {
96                     null
97                 }
98             }
99         }
100 
101     val panelComponent: StateFlow<ComponentName?> =
102         combine(allAvailableAndAuthorizedPanels, selectedPanel) { panels, selected ->
103                 val item =
104                     panels.firstOrNull { it.componentName == selected?.componentName }
105                         ?: panels.firstOrNull()
106                 item?.panelActivity
107             }
108             .stateIn(bgScope, SharingStarted.Eagerly, null)
109 
110     private data class PanelComponent(
111         val componentName: ComponentName,
112         val panelActivity: ComponentName,
113     )
114 }
115