xref: /aosp_15_r20/frameworks/base/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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 package com.android.systemui
17 
18 import android.content.ContentResolver
19 import android.content.Context
20 import android.content.res.Resources
21 import android.testing.TestableContext
22 import android.testing.TestableResources
23 import com.android.systemui.broadcast.BroadcastDispatcher
24 import com.android.systemui.broadcast.FakeBroadcastDispatcher
25 import com.android.systemui.coroutines.collectLastValue
26 import com.android.systemui.coroutines.collectValues
27 import com.android.systemui.dagger.SysUISingleton
28 import com.android.systemui.dagger.qualifiers.Application
29 import com.android.systemui.dagger.qualifiers.Main
30 import com.android.systemui.deviceentry.data.repository.FaceWakeUpTriggersConfigModule
31 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
32 import com.android.systemui.deviceentry.domain.interactor.SystemUIDeviceEntryFaceAuthInteractor
33 import com.android.systemui.dump.DumpManager
34 import com.android.systemui.keyguard.data.repository.PulseExpansionRepository
35 import com.android.systemui.keyguard.ui.composable.blueprint.DefaultBlueprintModule
36 import com.android.systemui.scene.SceneContainerFrameworkModule
37 import com.android.systemui.scene.shared.flag.SceneContainerFlag
38 import com.android.systemui.scene.shared.model.SceneContainerConfig
39 import com.android.systemui.scene.shared.model.SceneDataSource
40 import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
41 import com.android.systemui.shade.domain.interactor.BaseShadeInteractor
42 import com.android.systemui.shade.domain.interactor.ShadeInteractor
43 import com.android.systemui.shade.domain.interactor.ShadeInteractorImpl
44 import com.android.systemui.shade.domain.interactor.ShadeInteractorLegacyImpl
45 import com.android.systemui.shade.domain.interactor.ShadeInteractorSceneContainerImpl
46 import dagger.Binds
47 import dagger.Module
48 import dagger.Provides
49 import javax.inject.Provider
50 import kotlin.coroutines.CoroutineContext
51 import kotlin.coroutines.EmptyCoroutineContext
52 import kotlinx.coroutines.CoroutineScope
53 import kotlinx.coroutines.CoroutineStart
54 import kotlinx.coroutines.ExperimentalCoroutinesApi
55 import kotlinx.coroutines.flow.Flow
56 import kotlinx.coroutines.test.TestScope
57 import kotlinx.coroutines.test.runCurrent
58 import kotlinx.coroutines.test.runTest
59 
60 @Module(
61     includes =
62         [
63             TestMocksModule::class,
64             CoroutineTestScopeModule::class,
65             FakeSystemUiModule::class,
66             DefaultBlueprintModule::class,
67             SceneContainerFrameworkModule::class,
68             FaceWakeUpTriggersConfigModule::class,
69         ]
70 )
71 @Deprecated("Use Kosmos instead. See com.android.systemui.kosmos.Kosmos.")
72 interface SysUITestModule {
73 
bindTestableContextnull74     @Binds fun bindTestableContext(sysuiTestableContext: SysuiTestableContext): TestableContext
75 
76     @Binds fun bindContext(testableContext: TestableContext): Context
77 
78     @Binds @Application fun bindAppContext(context: Context): Context
79 
80     @Binds @Application fun bindAppResources(resources: Resources): Resources
81 
82     @Binds @Main fun bindMainResources(resources: Resources): Resources
83 
84     @Binds fun bindBroadcastDispatcher(fake: FakeBroadcastDispatcher): BroadcastDispatcher
85 
86     @Binds @SysUISingleton fun bindsShadeInteractor(sii: ShadeInteractorImpl): ShadeInteractor
87 
88     @Binds
89     @SysUISingleton
90     fun bindSceneDataSource(delegator: SceneDataSourceDelegator): SceneDataSource
91 
92     @Binds
93     fun provideFaceAuthInteractor(
94         sysUIFaceAuthInteractor: SystemUIDeviceEntryFaceAuthInteractor
95     ): DeviceEntryFaceAuthInteractor
96 
97     companion object {
98         @Provides
99         fun provideSysuiTestableContext(test: SysuiTestCase): SysuiTestableContext = test.context
100 
101         @Provides
102         fun provideTestableResources(context: TestableContext): TestableResources =
103             context.getOrCreateTestableResources()
104 
105         @Provides
106         fun provideResources(testableResources: TestableResources): Resources =
107             testableResources.resources
108 
109         @Provides
110         fun provideFakeBroadcastDispatcher(test: SysuiTestCase): FakeBroadcastDispatcher =
111             test.fakeBroadcastDispatcher
112 
113         @Provides
114         fun provideContentResolver(context: Context): ContentResolver = context.contentResolver
115 
116         @Provides
117         fun provideBaseShadeInteractor(
118             sceneContainerOn: Provider<ShadeInteractorSceneContainerImpl>,
119             sceneContainerOff: Provider<ShadeInteractorLegacyImpl>,
120         ): BaseShadeInteractor {
121             return if (SceneContainerFlag.isEnabled) {
122                 sceneContainerOn.get()
123             } else {
124                 sceneContainerOff.get()
125             }
126         }
127 
128         @Provides
129         @SysUISingleton
130         fun providesSceneDataSourceDelegator(
131             @Application applicationScope: CoroutineScope,
132             config: SceneContainerConfig,
133         ): SceneDataSourceDelegator {
134             return SceneDataSourceDelegator(applicationScope, config)
135         }
136 
137         @Provides
138         @SysUISingleton
139         fun providesPulseExpansionRepository(dumpManager: DumpManager): PulseExpansionRepository {
140             return PulseExpansionRepository(dumpManager)
141         }
142     }
143 }
144 
145 @Deprecated("Use Kosmos instead. See com.android.systemui.kosmos.Kosmos.")
146 interface SysUITestComponent<out T> {
147     val testScope: TestScope
148     val underTest: T
149 }
150 
151 @OptIn(ExperimentalCoroutinesApi::class)
runTestnull152 fun <T : SysUITestComponent<*>> T.runTest(block: suspend T.() -> Unit): Unit =
153     testScope.runTest {
154         // Access underTest immediately to force Dagger to instantiate it prior to the test running
155         underTest
156         runCurrent()
157         block()
158     }
159 
160 @OptIn(ExperimentalCoroutinesApi::class)
SysUITestComponentnull161 fun SysUITestComponent<*>.runCurrent() = testScope.runCurrent()
162 
163 fun <T> SysUITestComponent<*>.collectLastValue(
164     flow: Flow<T>,
165     context: CoroutineContext = EmptyCoroutineContext,
166     start: CoroutineStart = CoroutineStart.DEFAULT,
167 ) = testScope.collectLastValue(flow, context, start)
168 
169 fun <T> SysUITestComponent<*>.collectValues(
170     flow: Flow<T>,
171     context: CoroutineContext = EmptyCoroutineContext,
172     start: CoroutineStart = CoroutineStart.DEFAULT,
173 ) = testScope.collectValues(flow, context, start)
174 
175 val SysUITestComponent<*>.backgroundScope
176     get() = testScope.backgroundScope
177