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.keyguard
18 
19 import android.annotation.CurrentTimeMillisLong
20 import com.android.systemui.common.buffer.RingBuffer
21 import com.android.systemui.dump.DumpsysTableLogger
22 import com.android.systemui.dump.Row
23 
24 /** Verbose debug information. */
25 data class KeyguardFingerprintListenModel(
26     @CurrentTimeMillisLong override var timeMillis: Long = 0L,
27     override var userId: Int = 0,
28     override var listening: Boolean = false,
29     // keepSorted
30     var allowOnCurrentOccludingActivity: Boolean = false,
31     var alternateBouncerShowing: Boolean = false,
32     var biometricEnabledForUser: Boolean = false,
33     var bouncerIsOrWillShow: Boolean = false,
34     var canSkipBouncer: Boolean = false,
35     var credentialAttempted: Boolean = false,
36     var deviceInteractive: Boolean = false,
37     var dreaming: Boolean = false,
38     var fingerprintDisabled: Boolean = false,
39     var fingerprintLockedOut: Boolean = false,
40     var goingToSleep: Boolean = false,
41     var keyguardGoingAway: Boolean = false,
42     var keyguardIsVisible: Boolean = false,
43     var keyguardOccluded: Boolean = false,
44     var occludingAppRequestingFp: Boolean = false,
45     var shouldListenSfpsState: Boolean = false,
46     var shouldListenForFingerprintAssistant: Boolean = false,
47     var strongerAuthRequired: Boolean = false,
48     var switchingUser: Boolean = false,
49     var systemUser: Boolean = false,
50     var udfps: Boolean = false,
51     var userDoesNotHaveTrust: Boolean = false,
52 ) : KeyguardListenModel() {
53 
54     /** List of [String] to be used as a [Row] with [DumpsysTableLogger]. */
55     val asStringList: List<String> by lazy {
56         listOf(
57             DATE_FORMAT.format(timeMillis),
58             timeMillis.toString(),
59             userId.toString(),
60             listening.toString(),
61             // keep sorted
62             allowOnCurrentOccludingActivity.toString(),
63             alternateBouncerShowing.toString(),
64             biometricEnabledForUser.toString(),
65             bouncerIsOrWillShow.toString(),
66             canSkipBouncer.toString(),
67             credentialAttempted.toString(),
68             deviceInteractive.toString(),
69             dreaming.toString(),
70             fingerprintDisabled.toString(),
71             fingerprintLockedOut.toString(),
72             goingToSleep.toString(),
73             keyguardGoingAway.toString(),
74             keyguardIsVisible.toString(),
75             keyguardOccluded.toString(),
76             occludingAppRequestingFp.toString(),
77             shouldListenSfpsState.toString(),
78             shouldListenForFingerprintAssistant.toString(),
79             strongerAuthRequired.toString(),
80             switchingUser.toString(),
81             systemUser.toString(),
82             udfps.toString(),
83             userDoesNotHaveTrust.toString(),
84         )
85     }
86 
87     /**
88      * [RingBuffer] to store [KeyguardFingerprintListenModel]. After the buffer is full, it will
89      * recycle old events.
90      *
91      * Do not use [append] to add new elements. Instead use [insert], as it will recycle if
92      * necessary.
93      */
94     class Buffer {
95         private val buffer = RingBuffer(CAPACITY) { KeyguardFingerprintListenModel() }
96 
97         fun insert(model: KeyguardFingerprintListenModel) {
98             buffer.advance().apply {
99                 timeMillis = model.timeMillis
100                 userId = model.userId
101                 listening = model.listening
102                 // keep sorted
103                 allowOnCurrentOccludingActivity = model.allowOnCurrentOccludingActivity
104                 alternateBouncerShowing = model.alternateBouncerShowing
105                 biometricEnabledForUser = model.biometricEnabledForUser
106                 bouncerIsOrWillShow = model.bouncerIsOrWillShow
107                 canSkipBouncer = model.canSkipBouncer
108                 credentialAttempted = model.credentialAttempted
109                 deviceInteractive = model.deviceInteractive
110                 dreaming = model.dreaming
111                 fingerprintDisabled = model.fingerprintDisabled
112                 fingerprintLockedOut = model.fingerprintLockedOut
113                 goingToSleep = model.goingToSleep
114                 keyguardGoingAway = model.keyguardGoingAway
115                 keyguardIsVisible = model.keyguardIsVisible
116                 keyguardOccluded = model.keyguardOccluded
117                 occludingAppRequestingFp = model.occludingAppRequestingFp
118                 shouldListenSfpsState = model.shouldListenSfpsState
119                 shouldListenForFingerprintAssistant = model.shouldListenForFingerprintAssistant
120                 strongerAuthRequired = model.strongerAuthRequired
121                 switchingUser = model.switchingUser
122                 systemUser = model.systemUser
123                 udfps = model.udfps
124                 userDoesNotHaveTrust = model.userDoesNotHaveTrust
125             }
126         }
127 
128         /**
129          * Returns the content of the buffer (sorted from latest to newest).
130          *
131          * @see KeyguardFingerprintListenModel.asStringList
132          */
133         fun toList(): List<Row> {
134             return buffer.asSequence().map { it.asStringList }.toList()
135         }
136     }
137 
138     companion object {
139         const val CAPACITY = 20 // number of logs to retain
140 
141         /** Headers for dumping a table using [DumpsysTableLogger]. */
142         @JvmField
143         val TABLE_HEADERS =
144             listOf(
145                 "timestamp",
146                 "time_millis",
147                 "userId",
148                 "listening",
149                 // keep sorted
150                 "allowOnCurrentOccludingActivity",
151                 "alternateBouncerShowing",
152                 "biometricAllowedForUser",
153                 "bouncerIsOrWillShow",
154                 "canSkipBouncer",
155                 "credentialAttempted",
156                 "deviceInteractive",
157                 "dreaming",
158                 "fingerprintDisabled",
159                 "fingerprintLockedOut",
160                 "goingToSleep",
161                 "keyguardGoingAway",
162                 "keyguardIsVisible",
163                 "keyguardOccluded",
164                 "occludingAppRequestingFp",
165                 "shouldListenSidFingerprintState",
166                 "shouldListenForFingerprintAssistant",
167                 "strongAuthRequired",
168                 "switchingUser",
169                 "systemUser",
170                 "underDisplayFingerprint",
171                 "userDoesNotHaveTrust",
172             )
173     }
174 }
175