1 /*
2  * Copyright (C) 2022 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.bouncer.ui.viewmodel
18 
19 import android.os.Looper
20 import androidx.test.ext.junit.runners.AndroidJUnit4
21 import androidx.test.filters.SmallTest
22 import com.android.keyguard.KeyguardSecurityModel
23 import com.android.keyguard.KeyguardUpdateMonitor
24 import com.android.systemui.RoboPilotTest
25 import com.android.systemui.SysuiTestCase
26 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
27 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
28 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
29 import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
30 import com.android.systemui.bouncer.ui.BouncerView
31 import com.android.systemui.classifier.FalsingCollector
32 import com.android.systemui.coroutines.collectLastValue
33 import com.android.systemui.coroutines.collectValues
34 import com.android.systemui.flags.FakeFeatureFlags
35 import com.android.systemui.flags.Flags
36 import com.android.systemui.keyguard.DismissCallbackRegistry
37 import com.android.systemui.keyguard.data.repository.TrustRepository
38 import com.android.systemui.statusbar.phone.KeyguardBypassController
39 import com.android.systemui.statusbar.policy.KeyguardStateController
40 import com.android.systemui.utils.os.FakeHandler
41 import com.google.common.truth.Truth.assertThat
42 import kotlinx.coroutines.flow.launchIn
43 import kotlinx.coroutines.flow.onEach
44 import kotlinx.coroutines.test.TestScope
45 import kotlinx.coroutines.test.runCurrent
46 import kotlinx.coroutines.test.runTest
47 import org.junit.Before
48 import org.junit.Test
49 import org.junit.runner.RunWith
50 import org.mockito.Mock
51 import org.mockito.Mockito
52 import org.mockito.MockitoAnnotations
53 
54 @SmallTest
55 @RoboPilotTest
56 @RunWith(AndroidJUnit4::class)
57 @kotlinx.coroutines.ExperimentalCoroutinesApi
58 class KeyguardBouncerViewModelTest : SysuiTestCase() {
59     lateinit var underTest: KeyguardBouncerViewModel
60     lateinit var bouncerInteractor: PrimaryBouncerInteractor
61     @Mock lateinit var bouncerView: BouncerView
62     @Mock private lateinit var keyguardStateController: KeyguardStateController
63     @Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel
64     @Mock private lateinit var primaryBouncerCallbackInteractor: PrimaryBouncerCallbackInteractor
65     @Mock private lateinit var falsingCollector: FalsingCollector
66     @Mock private lateinit var dismissCallbackRegistry: DismissCallbackRegistry
67     @Mock private lateinit var keyguardBypassController: KeyguardBypassController
68     @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
69     private val mainHandler = FakeHandler(Looper.getMainLooper())
70     val repository = FakeKeyguardBouncerRepository()
71 
72     @Before
73     fun setup() {
74         MockitoAnnotations.initMocks(this)
75         bouncerInteractor =
76             PrimaryBouncerInteractor(
77                 repository,
78                 bouncerView,
79                 mainHandler,
80                 keyguardStateController,
81                 keyguardSecurityModel,
82                 primaryBouncerCallbackInteractor,
83                 falsingCollector,
84                 dismissCallbackRegistry,
85                 context,
86                 keyguardUpdateMonitor,
87                 Mockito.mock(TrustRepository::class.java),
88                 FakeFeatureFlags().apply { set(Flags.DELAY_BOUNCER, true) },
89                 TestScope().backgroundScope,
90             )
91         underTest = KeyguardBouncerViewModel(bouncerView, bouncerInteractor)
92     }
93 
94     @Test
95     fun setMessage() = runTest {
96         var message: BouncerShowMessageModel? = null
97         val job = underTest.bouncerShowMessage.onEach { message = it }.launchIn(this)
98 
99         repository.setShowMessage(BouncerShowMessageModel("abc", null))
100         // Run the tasks that are pending at this point of virtual time.
101         runCurrent()
102         assertThat(message?.message).isEqualTo("abc")
103         job.cancel()
104     }
105 
106     @Test
107     fun shouldUpdateSideFps_show() = runTest {
108         var count = 0
109         val job = underTest.shouldUpdateSideFps.onEach { count++ }.launchIn(this)
110         repository.setPrimaryShow(true)
111         // Run the tasks that are pending at this point of virtual time.
112         runCurrent()
113         assertThat(count).isEqualTo(1)
114         job.cancel()
115     }
116 
117     @Test
118     fun shouldUpdateSideFps_hide() = runTest {
119         repository.setPrimaryShow(true)
120         var count = 0
121         val job = underTest.shouldUpdateSideFps.onEach { count++ }.launchIn(this)
122         repository.setPrimaryShow(false)
123         // Run the tasks that are pending at this point of virtual time.
124         runCurrent()
125         assertThat(count).isEqualTo(1)
126         job.cancel()
127     }
128 
129     @Test
130     fun sideFpsShowing() = runTest {
131         var sideFpsIsShowing = false
132         val job = underTest.sideFpsShowing.onEach { sideFpsIsShowing = it }.launchIn(this)
133         repository.setSideFpsShowing(true)
134         // Run the tasks that are pending at this point of virtual time.
135         runCurrent()
136         assertThat(sideFpsIsShowing).isEqualTo(true)
137         job.cancel()
138     }
139 
140     @Test
141     fun isShowing() = runTest {
142         var isShowing: Boolean? = null
143         val job = underTest.isShowing.onEach { isShowing = it }.launchIn(this)
144         repository.setPrimaryShow(true)
145         // Run the tasks that are pending at this point of virtual time.
146         runCurrent()
147         assertThat(isShowing).isEqualTo(true)
148         job.cancel()
149     }
150 
151     @Test
152     fun isNotShowing() = runTest {
153         var isShowing: Boolean? = null
154         val job = underTest.isShowing.onEach { isShowing = it }.launchIn(this)
155         repository.setPrimaryShow(false)
156         // Run the tasks that are pending at this point of virtual time.
157         runCurrent()
158         assertThat(isShowing).isEqualTo(false)
159         job.cancel()
160     }
161 
162     @Test
163     fun keyguardPosition_noValueSet_emptyByDefault() = runTest {
164         val positionValues by collectValues(underTest.keyguardPosition)
165 
166         runCurrent()
167 
168         assertThat(positionValues).isEmpty()
169     }
170 
171     @Test
172     fun keyguardPosition_valueSet_returnsValue() = runTest {
173         val position by collectLastValue(underTest.keyguardPosition)
174         runCurrent()
175 
176         repository.setKeyguardPosition(123f)
177         runCurrent()
178 
179         assertThat(position).isEqualTo(123f)
180     }
181 }
182