1 /*
2  * Copyright (C) 2023 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.qs.tiles.base.viewmodel
18 
19 import com.android.systemui.dagger.qualifiers.Background
20 import com.android.systemui.plugins.FalsingManager
21 import com.android.systemui.qs.pipeline.shared.TileSpec
22 import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics
23 import com.android.systemui.qs.tiles.base.interactor.DisabledByPolicyInteractor
24 import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
25 import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
26 import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
27 import com.android.systemui.qs.tiles.base.logging.QSTileLogger
28 import com.android.systemui.qs.tiles.impl.custom.di.CustomTileComponent
29 import com.android.systemui.qs.tiles.impl.custom.di.QSTileConfigModule
30 import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel
31 import com.android.systemui.qs.tiles.impl.di.QSTileComponent
32 import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider
33 import com.android.systemui.qs.tiles.viewmodel.QSTileState
34 import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
35 import com.android.systemui.user.data.repository.UserRepository
36 import com.android.systemui.util.time.SystemClock
37 import javax.inject.Inject
38 import kotlinx.coroutines.CoroutineDispatcher
39 
40 /**
41  * Factory to create an appropriate [QSTileViewModelImpl] instance depending on your circumstances.
42  *
43  * @see [QSTileViewModelFactory.Component]
44  * @see [QSTileViewModelFactory.Static]
45  */
46 sealed interface QSTileViewModelFactory<T> {
47 
48     /**
49      * This factory allows you to pass an instance of [QSTileComponent] to a view model effectively
50      * binding them together. This achieves a DI scope that lives along the instance of
51      * [QSTileViewModelImpl].
52      */
53     class Component
54     @Inject
55     constructor(
56         private val disabledByPolicyInteractor: DisabledByPolicyInteractor,
57         private val userRepository: UserRepository,
58         private val falsingManager: FalsingManager,
59         private val qsTileAnalytics: QSTileAnalytics,
60         private val qsTileLogger: QSTileLogger,
61         private val qsTileConfigProvider: QSTileConfigProvider,
62         private val systemClock: SystemClock,
63         @Background private val backgroundDispatcher: CoroutineDispatcher,
64         private val customTileComponentBuilder: CustomTileComponent.Builder,
65     ) : QSTileViewModelFactory<CustomTileDataModel> {
66 
67         /**
68          * Creates [QSTileViewModelImpl] based on the interactors obtained from [QSTileComponent].
69          * Reference of that [QSTileComponent] is then stored along the view model.
70          */
createnull71         fun create(
72             tileSpec: TileSpec,
73         ): QSTileViewModel {
74             val config = qsTileConfigProvider.getConfig(tileSpec.spec)
75             val component =
76                 customTileComponentBuilder.qsTileConfigModule(QSTileConfigModule(config)).build()
77             return QSTileViewModelImpl(
78                 config,
79                 component::userActionInteractor,
80                 component::dataInteractor,
81                 component::dataToStateMapper,
82                 disabledByPolicyInteractor,
83                 userRepository,
84                 falsingManager,
85                 qsTileAnalytics,
86                 qsTileLogger,
87                 systemClock,
88                 backgroundDispatcher,
89                 component.coroutineScope(),
90             )
91         }
92     }
93 
94     /**
95      * This factory passes by necessary implementations to the [QSTileViewModelImpl]. This is a
96      * default choice for most of the tiles.
97      */
98     class Static<T>
99     @Inject
100     constructor(
101         private val disabledByPolicyInteractor: DisabledByPolicyInteractor,
102         private val userRepository: UserRepository,
103         private val falsingManager: FalsingManager,
104         private val qsTileAnalytics: QSTileAnalytics,
105         private val qsTileLogger: QSTileLogger,
106         private val qsTileConfigProvider: QSTileConfigProvider,
107         private val systemClock: SystemClock,
108         @Background private val backgroundDispatcher: CoroutineDispatcher,
109         private val coroutineScopeFactory: QSTileCoroutineScopeFactory,
110     ) : QSTileViewModelFactory<T> {
111 
112         /**
113          * @param tileSpec of the created tile.
114          * @param userActionInteractor encapsulates user input processing logic. Use it to start
115          *   activities, show dialogs or otherwise update the tile state.
116          * @param tileDataInteractor provides [DATA_TYPE] and its availability.
117          * @param mapper maps [DATA_TYPE] to the [QSTileState] that is then displayed by the View
118          *   layer. It's called in [backgroundDispatcher], so it's safe to perform long running
119          *   operations there.
120          */
createnull121         fun create(
122             tileSpec: TileSpec,
123             userActionInteractor: QSTileUserActionInteractor<T>,
124             tileDataInteractor: QSTileDataInteractor<T>,
125             mapper: QSTileDataToStateMapper<T>,
126         ): QSTileViewModelImpl<T> =
127             QSTileViewModelImpl(
128                 qsTileConfigProvider.getConfig(tileSpec.spec),
129                 { userActionInteractor },
<lambda>null130                 { tileDataInteractor },
<lambda>null131                 { mapper },
132                 disabledByPolicyInteractor,
133                 userRepository,
134                 falsingManager,
135                 qsTileAnalytics,
136                 qsTileLogger,
137                 systemClock,
138                 backgroundDispatcher,
139                 coroutineScopeFactory.create(),
140             )
141     }
142 }
143