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