1 /*
2  * Copyright (C) 2020 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.controls.controller
18 
19 import android.content.ComponentName
20 import android.service.controls.Control
21 import android.service.controls.ControlsProviderService
22 import android.service.controls.actions.ControlAction
23 import com.android.systemui.controls.ControlStatus
24 import com.android.systemui.util.UserAwareController
25 import com.android.systemui.controls.management.ControlsFavoritingActivity
26 import com.android.systemui.controls.ui.ControlsUiController
27 import java.util.function.Consumer
28 
29 /**
30  * Controller to handle communication between different parts of the controls system.
31  *
32  * This controller is in charge of:
33  *  * Keeping track of favorites
34  *  * Determining and keeping track of whether controls are enabled
35  *  * Listening for user change and propagating that message in the system
36  *  * Communicate between the UI and the [ControlsBindingController]
37  *
38  *  This controller being a [UserAwareController] means that all operations will be conducted on
39  *  information for the current user only.
40  */
41 interface ControlsController : UserAwareController {
42 
43     // SERVICE COMMUNICATION
44 
45     /**
46      * Load all available [Control] for a given service.
47      *
48      * @param componentName the [ComponentName] of the [ControlsProviderService] to load from
49      * @param dataCallback a callback in which to retrieve the result
50      * @param cancelWrapper a callback to receive a [Runnable] that can be run to cancel the
51      *                      request
52      */
53     fun loadForComponent(
54         componentName: ComponentName,
55         dataCallback: Consumer<LoadData>,
56         cancelWrapper: Consumer<Runnable>
57     )
58 
59     /**
60      * Request to subscribe for favorited controls per structure
61      *
62      * @param structureInfo structure to limit the subscription to
63      * @see [ControlsBindingController.subscribe]
64      */
65     fun subscribeToFavorites(structureInfo: StructureInfo)
66 
67     /**
68      * Request to unsubscribe to the current provider.
69      *
70      * @see [ControlsBindingController.unsubscribe]
71      */
72     fun unsubscribe()
73 
74     /**
75      * Notify a [ControlsProviderService] that an action has been performed on a [Control].
76      *
77      * @param componentName the name of the service that provides the [Control]
78      * @param controlInfo information of the [Control] receiving the action
79      * @param action action performed on the [Control]
80      * @see [ControlsBindingController.action]
81      */
82     fun action(componentName: ComponentName, controlInfo: ControlInfo, action: ControlAction)
83 
84     /**
85      * Refresh the status of a [Control] with information provided from the service.
86      *
87      * @param componentName the name of the service that provides the [Control]
88      * @param control a stateful [Control] with updated information
89      * @see [ControlsUiController.onRefreshState]
90      */
91     fun refreshStatus(componentName: ComponentName, control: Control)
92 
93     /**
94      * Indicate the result of a [ControlAction] performed on a [Control].
95      *
96      * @param componentName the name of the service that provides the [Control]
97      * @param controlId the id of the [Control] the actioned was performed on
98      * @param response the result of the action.
99      * @see [ControlsUiController.onActionResponse]
100      */
101     fun onActionResponse(
102         componentName: ComponentName,
103         controlId: String,
104         @ControlAction.ResponseResult response: Int
105     )
106 
107     // FAVORITE MANAGEMENT
108 
109     /**
110      * Send a request to seed favorites into the persisted XML file
111      *
112      * @param componentNames the list of components to seed controls from
113      * @param callback one [SeedResponse] per componentName
114      */
115     fun seedFavoritesForComponents(
116         componentNames: List<ComponentName>,
117         callback: Consumer<SeedResponse>
118     )
119 
120     /**
121      * Callback to be informed when the seeding process has finished
122      *
123      * @param callback consumer accepts true if successful
124      * @return true if seeding is in progress and the callback was added
125      */
126     fun addSeedingFavoritesCallback(callback: Consumer<Boolean>): Boolean
127 
128     /**
129      * Get all the favorites.
130      *
131      * @return a list of the structures that have at least one favorited control
132      */
133     fun getFavorites(): List<StructureInfo>
134 
135     /**
136      * Get all the favorites for a given component.
137      *
138      * @param componentName the name of the service that provides the [Control]
139      * @return a list of the structures that have at least one favorited control
140      */
141     fun getFavoritesForComponent(componentName: ComponentName): List<StructureInfo>
142 
143     /**
144      * Get all the favorites for a given structure.
145      *
146      * @param componentName the name of the service that provides the [Control]
147      * @param structureName the name of the structure
148      * @return a list of the current favorites in that structure
149      */
150     fun getFavoritesForStructure(
151         componentName: ComponentName,
152         structureName: CharSequence
153     ): List<ControlInfo>
154 
155     /**
156      * Adds a single favorite to a given component and structure
157      * @param componentName the name of the service that provides the [Control]
158      * @param structureName the name of the structure that holds the [Control]
159      * @param controlInfo persistent information about the [Control] to be added.
160      */
161     fun addFavorite(
162         componentName: ComponentName,
163         structureName: CharSequence,
164         controlInfo: ControlInfo
165     )
166 
167     /**
168      * Replaces the favorites for the given structure.
169      *
170      * Calling this method will eliminate the previous selection of favorites and replace it with a
171      * new one.
172      *
173      * @param structureInfo common structure for all of the favorited controls
174      */
175     fun replaceFavoritesForStructure(structureInfo: StructureInfo)
176 
177     /**
178      * Return the number of favorites for a given component.
179      *
180      * This call returns the same as `getFavoritesForComponent(componentName).size`.
181      *
182      * @param componentName the name of the component
183      * @return the number of current favorites for the given component
184      */
185     fun countFavoritesForComponent(componentName: ComponentName): Int
186 
187     /** See [ControlsUiController.getPreferredStructure]. */
188     fun getPreferredStructure(): StructureInfo
189 
190     /**
191      * Interface for structure to pass data to [ControlsFavoritingActivity].
192      */
193     interface LoadData {
194         /**
195          * All of the available controls for the loaded [ControlsProviderService].
196          *
197          * This will indicate if they are currently a favorite and whether they were removed (a
198          * favorite but not retrieved on load).
199          */
200         val allControls: List<ControlStatus>
201 
202         /**
203          * Ordered list of ids of favorite controls.
204          */
205         val favoritesIds: List<String>
206 
207         /**
208          * Whether there was an error in loading.
209          *
210          * In this case, [allControls] will only contain those that were favorited and will not be
211          * marked as removed.
212          */
213         val errorOnLoad: Boolean
214     }
215 }
216 
217 /**
218  * Creates a basic implementation of a [LoadData].
219  */
220 fun createLoadDataObject(
221     allControls: List<ControlStatus>,
222     favorites: List<String>,
223     error: Boolean = false
224 ): ControlsController.LoadData {
225     return object : ControlsController.LoadData {
226         override val allControls = allControls
227         override val favoritesIds = favorites
228         override val errorOnLoad = error
229     }
230 }
231 
232 data class SeedResponse(val packageName: String, val accepted: Boolean)
233