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.scene
18 
19 import android.content.pm.UserInfo
20 import com.android.systemui.SysuiTestCase
21 import com.android.systemui.authentication.data.model.AuthenticationMethodModel as DataLayerAuthenticationMethodModel
22 import com.android.systemui.authentication.data.repository.AuthenticationRepository
23 import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
24 import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
25 import com.android.systemui.authentication.domain.model.AuthenticationMethodModel as DomainLayerAuthenticationMethodModel
26 import com.android.systemui.bouncer.data.repository.BouncerRepository
27 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
28 import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
29 import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
30 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
31 import com.android.systemui.flags.FakeFeatureFlags
32 import com.android.systemui.flags.Flags
33 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
34 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
35 import com.android.systemui.keyguard.data.repository.KeyguardRepository
36 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
37 import com.android.systemui.keyguard.shared.model.WakeSleepReason
38 import com.android.systemui.keyguard.shared.model.WakefulnessModel
39 import com.android.systemui.keyguard.shared.model.WakefulnessState
40 import com.android.systemui.scene.data.repository.SceneContainerRepository
41 import com.android.systemui.scene.domain.interactor.SceneInteractor
42 import com.android.systemui.scene.shared.model.SceneContainerConfig
43 import com.android.systemui.scene.shared.model.SceneKey
44 import com.android.systemui.user.data.repository.FakeUserRepository
45 import com.android.systemui.user.data.repository.UserRepository
46 import com.android.systemui.util.mockito.mock
47 import com.android.systemui.util.mockito.whenever
48 import kotlinx.coroutines.CoroutineScope
49 import kotlinx.coroutines.ExperimentalCoroutinesApi
50 import kotlinx.coroutines.runBlocking
51 import kotlinx.coroutines.test.StandardTestDispatcher
52 import kotlinx.coroutines.test.TestScope
53 import kotlinx.coroutines.test.currentTime
54 
55 /**
56  * Utilities for creating scene container framework related repositories, interactors, and
57  * view-models for tests.
58  */
59 @OptIn(ExperimentalCoroutinesApi::class)
60 class SceneTestUtils(
61     test: SysuiTestCase,
62 ) {
63     val testDispatcher = StandardTestDispatcher()
64     val testScope = TestScope(testDispatcher)
65     val featureFlags =
66         FakeFeatureFlags().apply {
67             set(Flags.SCENE_CONTAINER, true)
68             set(Flags.FACE_AUTH_REFACTOR, false)
69         }
70     private val userRepository: UserRepository by lazy {
71         FakeUserRepository().apply {
72             val users = listOf(UserInfo(/* id=  */ 0, "name", /* flags= */ 0))
73             setUserInfos(users)
74             runBlocking { setSelectedUserInfo(users.first()) }
75         }
76     }
77 
78     val authenticationRepository: FakeAuthenticationRepository by lazy {
79         FakeAuthenticationRepository(
80             currentTime = { testScope.currentTime },
81         )
82     }
83     val keyguardRepository: FakeKeyguardRepository by lazy {
84         FakeKeyguardRepository().apply {
85             setWakefulnessModel(
86                 WakefulnessModel(
87                     WakefulnessState.AWAKE,
88                     WakeSleepReason.OTHER,
89                     WakeSleepReason.OTHER,
90                 )
91             )
92         }
93     }
94 
95     private val context = test.context
96 
97     fun fakeSceneContainerRepository(
98         containerConfig: SceneContainerConfig = fakeSceneContainerConfig(),
99     ): SceneContainerRepository {
100         return SceneContainerRepository(applicationScope(), containerConfig)
101     }
102 
103     fun fakeSceneKeys(): List<SceneKey> {
104         return listOf(
105             SceneKey.QuickSettings,
106             SceneKey.Shade,
107             SceneKey.Lockscreen,
108             SceneKey.Bouncer,
109             SceneKey.Gone,
110         )
111     }
112 
113     fun fakeSceneContainerConfig(
114         sceneKeys: List<SceneKey> = fakeSceneKeys(),
115     ): SceneContainerConfig {
116         return SceneContainerConfig(
117             sceneKeys = sceneKeys,
118             initialSceneKey = SceneKey.Lockscreen,
119         )
120     }
121 
122     fun sceneInteractor(
123         repository: SceneContainerRepository = fakeSceneContainerRepository()
124     ): SceneInteractor {
125         return SceneInteractor(
126             applicationScope = applicationScope(),
127             repository = repository,
128             logger = mock(),
129         )
130     }
131 
132     fun authenticationRepository(): FakeAuthenticationRepository {
133         return authenticationRepository
134     }
135 
136     fun authenticationInteractor(
137         repository: AuthenticationRepository,
138         sceneInteractor: SceneInteractor = sceneInteractor(),
139     ): AuthenticationInteractor {
140         return AuthenticationInteractor(
141             applicationScope = applicationScope(),
142             repository = repository,
143             backgroundDispatcher = testDispatcher,
144             userRepository = userRepository,
145             keyguardRepository = keyguardRepository,
146             sceneInteractor = sceneInteractor,
147             clock = mock { whenever(elapsedRealtime()).thenAnswer { testScope.currentTime } }
148         )
149     }
150 
151     fun keyguardRepository(): FakeKeyguardRepository {
152         return keyguardRepository
153     }
154 
155     fun keyguardInteractor(repository: KeyguardRepository): KeyguardInteractor {
156         return KeyguardInteractor(
157             repository = repository,
158             commandQueue = FakeCommandQueue(),
159             featureFlags = featureFlags,
160             bouncerRepository = FakeKeyguardBouncerRepository(),
161             configurationRepository = FakeConfigurationRepository()
162         )
163     }
164 
165     fun bouncerInteractor(
166         authenticationInteractor: AuthenticationInteractor,
167         sceneInteractor: SceneInteractor,
168     ): BouncerInteractor {
169         return BouncerInteractor(
170             applicationScope = applicationScope(),
171             applicationContext = context,
172             repository = BouncerRepository(),
173             authenticationInteractor = authenticationInteractor,
174             sceneInteractor = sceneInteractor,
175             featureFlags = featureFlags,
176         )
177     }
178 
179     fun bouncerViewModel(
180         bouncerInteractor: BouncerInteractor,
181         authenticationInteractor: AuthenticationInteractor,
182     ): BouncerViewModel {
183         return BouncerViewModel(
184             applicationContext = context,
185             applicationScope = applicationScope(),
186             bouncerInteractor = bouncerInteractor,
187             authenticationInteractor = authenticationInteractor,
188             featureFlags = featureFlags,
189         )
190     }
191 
192     private fun applicationScope(): CoroutineScope {
193         return testScope.backgroundScope
194     }
195 
196     companion object {
197         fun DomainLayerAuthenticationMethodModel.toDataLayer(): DataLayerAuthenticationMethodModel {
198             return when (this) {
199                 DomainLayerAuthenticationMethodModel.None -> DataLayerAuthenticationMethodModel.None
200                 DomainLayerAuthenticationMethodModel.Swipe ->
201                     DataLayerAuthenticationMethodModel.None
202                 DomainLayerAuthenticationMethodModel.Pin -> DataLayerAuthenticationMethodModel.Pin
203                 DomainLayerAuthenticationMethodModel.Password ->
204                     DataLayerAuthenticationMethodModel.Password
205                 DomainLayerAuthenticationMethodModel.Pattern ->
206                     DataLayerAuthenticationMethodModel.Pattern
207             }
208         }
209     }
210 }
211