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.biometrics
18 
19 import androidx.test.ext.junit.runners.AndroidJUnit4
20 import androidx.test.filters.SmallTest
21 import com.android.keyguard.logging.BiometricMessageDeferralLogger
22 import com.android.systemui.RoboPilotTest
23 import com.android.systemui.SysuiTestCase
24 import com.android.systemui.dump.DumpManager
25 import org.junit.Assert.assertEquals
26 import org.junit.Assert.assertFalse
27 import org.junit.Assert.assertNull
28 import org.junit.Assert.assertTrue
29 import org.junit.Before
30 import org.junit.Test
31 import org.junit.runner.RunWith
32 import org.mockito.Mock
33 import org.mockito.Mockito.verify
34 import org.mockito.MockitoAnnotations
35 
36 @SmallTest
37 @RoboPilotTest
38 @RunWith(AndroidJUnit4::class)
39 class FaceHelpMessageDeferralTest : SysuiTestCase() {
40     val threshold = .75f
41     @Mock lateinit var logger: BiometricMessageDeferralLogger
42     @Mock lateinit var dumpManager: DumpManager
43 
44     @Before
45     fun setUp() {
46         MockitoAnnotations.initMocks(this)
47     }
48 
49     @Test
50     fun testProcessFrame_logs() {
51         val biometricMessageDeferral = createMsgDeferral(setOf(1))
52         biometricMessageDeferral.processFrame(1)
53         verify(logger).logFrameProcessed(1, 1, "1")
54     }
55 
56     @Test
57     fun testUpdateMessage_logs() {
58         val biometricMessageDeferral = createMsgDeferral(setOf(1))
59         biometricMessageDeferral.updateMessage(1, "hi")
60         verify(logger).logUpdateMessage(1, "hi")
61     }
62 
63     @Test
64     fun testReset_logs() {
65         val biometricMessageDeferral = createMsgDeferral(setOf(1))
66         biometricMessageDeferral.reset()
67         verify(logger).reset()
68     }
69 
70     @Test
71     fun testProcessNoMessages_noDeferredMessage() {
72         val biometricMessageDeferral = createMsgDeferral(emptySet())
73 
74         assertNull(biometricMessageDeferral.getDeferredMessage())
75     }
76 
77     @Test
78     fun testProcessNonDeferredMessages_noDeferredMessage() {
79         val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
80 
81         // WHEN there are no deferred messages processed
82         for (i in 0..3) {
83             biometricMessageDeferral.processFrame(4)
84             biometricMessageDeferral.updateMessage(4, "test")
85         }
86 
87         // THEN getDeferredMessage is null
88         assertNull(biometricMessageDeferral.getDeferredMessage())
89     }
90 
91     @Test
92     fun testProcessMessagesWithDeferredMessage_deferredMessageWasNeverGivenAString() {
93         val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
94 
95         biometricMessageDeferral.processFrame(1)
96 
97         assertNull(biometricMessageDeferral.getDeferredMessage())
98     }
99 
100     @Test
101     fun testAllProcessedMessagesWereDeferred() {
102         val biometricMessageDeferral = createMsgDeferral(setOf(1))
103 
104         // WHEN all the processed messages are a deferred message
105         for (i in 0..3) {
106             biometricMessageDeferral.processFrame(1)
107             biometricMessageDeferral.updateMessage(1, "test")
108         }
109 
110         // THEN deferredMessage will return the string associated with the deferred msgId
111         assertEquals("test", biometricMessageDeferral.getDeferredMessage())
112     }
113 
114     @Test
115     fun testReturnsMostFrequentDeferredMessage() {
116         val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
117 
118         // WHEN there's 80%of the messages are msgId=1 and 20% is msgId=2
119         biometricMessageDeferral.processFrame(1)
120         biometricMessageDeferral.processFrame(1)
121         biometricMessageDeferral.processFrame(1)
122         biometricMessageDeferral.processFrame(1)
123         biometricMessageDeferral.updateMessage(1, "msgId-1")
124 
125         biometricMessageDeferral.processFrame(2)
126         biometricMessageDeferral.updateMessage(2, "msgId-2")
127 
128         // THEN the most frequent deferred message is that meets the threshold is returned
129         assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage())
130     }
131 
132     @Test
133     fun testDeferredMessage_mustMeetThreshold() {
134         val biometricMessageDeferral = createMsgDeferral(setOf(1))
135 
136         // WHEN more nonDeferredMessages are shown than the deferred message
137         val totalMessages = 10
138         val nonDeferredMessagesCount = (totalMessages * threshold).toInt() + 1
139         for (i in 0 until nonDeferredMessagesCount) {
140             biometricMessageDeferral.processFrame(4)
141             biometricMessageDeferral.updateMessage(4, "non-deferred-msg")
142         }
143         for (i in nonDeferredMessagesCount until totalMessages) {
144             biometricMessageDeferral.processFrame(1)
145             biometricMessageDeferral.updateMessage(1, "msgId-1")
146         }
147 
148         // THEN there's no deferred message because it didn't meet the threshold
149         assertNull(biometricMessageDeferral.getDeferredMessage())
150     }
151 
152     @Test
153     fun testResetClearsOutCounts() {
154         val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
155 
156         // GIVEN two msgId=1 events processed
157         biometricMessageDeferral.processFrame(
158             1,
159         )
160         biometricMessageDeferral.updateMessage(1, "msgId-1")
161         biometricMessageDeferral.processFrame(1)
162         biometricMessageDeferral.updateMessage(1, "msgId-1")
163 
164         // WHEN counts are reset and then a single deferred message is processed (msgId=2)
165         biometricMessageDeferral.reset()
166         biometricMessageDeferral.processFrame(2)
167         biometricMessageDeferral.updateMessage(2, "msgId-2")
168 
169         // THEN msgId-2 is the deferred message since the two msgId=1 events were reset
170         assertEquals("msgId-2", biometricMessageDeferral.getDeferredMessage())
171     }
172 
173     @Test
174     fun testShouldDefer() {
175         // GIVEN should defer msgIds 1 and 2
176         val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
177 
178         // THEN shouldDefer returns true for ids 1 & 2
179         assertTrue(biometricMessageDeferral.shouldDefer(1))
180         assertTrue(biometricMessageDeferral.shouldDefer(2))
181 
182         // THEN should defer returns false for ids 3 & 4
183         assertFalse(biometricMessageDeferral.shouldDefer(3))
184         assertFalse(biometricMessageDeferral.shouldDefer(4))
185     }
186 
187     @Test
188     fun testDeferredMessage_meetThresholdWithIgnoredFrames() {
189         val biometricMessageDeferral =
190             createMsgDeferral(
191                 messagesToDefer = setOf(1),
192                 acquiredInfoToIgnore = setOf(4),
193             )
194 
195         // WHEN more nonDeferredMessages are shown than the deferred message; HOWEVER the
196         // nonDeferredMessages are in acquiredInfoToIgnore
197         val totalMessages = 10
198         val nonDeferredMessagesCount = (totalMessages * threshold).toInt() + 1
199         for (i in 0 until nonDeferredMessagesCount) {
200             biometricMessageDeferral.processFrame(4)
201             biometricMessageDeferral.updateMessage(4, "non-deferred-msg")
202         }
203         for (i in nonDeferredMessagesCount until totalMessages) {
204             biometricMessageDeferral.processFrame(1)
205             biometricMessageDeferral.updateMessage(1, "msgId-1")
206         }
207 
208         // THEN the deferred message met the threshold excluding the acquiredInfoToIgnore,
209         // so the message id deferred
210         assertTrue(biometricMessageDeferral.shouldDefer(1))
211         assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage())
212     }
213 
214     private fun createMsgDeferral(
215         messagesToDefer: Set<Int>,
216         acquiredInfoToIgnore: Set<Int> = emptySet(),
217     ): BiometricMessageDeferral {
218         return BiometricMessageDeferral(
219             messagesToDefer,
220             acquiredInfoToIgnore,
221             threshold,
222             logger,
223             dumpManager,
224         )
225     }
226 }
227