Merge "[Bouncer] Add bouncer log buffer." into tm-qpr-dev
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
index 783f752..90f3c7d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
@@ -16,23 +16,36 @@
package com.android.systemui.keyguard.data.repository
-import com.android.keyguard.KeyguardUpdateMonitor
+import android.os.Build
import com.android.keyguard.ViewMediatorCallback
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel
+import com.android.systemui.log.dagger.BouncerLog
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.phone.KeyguardBouncer
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
-/** Encapsulates app state for the lock screen primary and alternate bouncer. */
+/**
+ * Encapsulates app state for the lock screen primary and alternate bouncer.
+ *
+ * Make sure to add newly added flows to the logger.
+ */
@SysUISingleton
class KeyguardBouncerRepository
@Inject
constructor(
private val viewMediatorCallback: ViewMediatorCallback,
- keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ @Application private val applicationScope: CoroutineScope,
+ @BouncerLog private val buffer: TableLogBuffer,
) {
/** Values associated with the PrimaryBouncer (pin/pattern/password) input. */
private val _primaryBouncerVisible = MutableStateFlow(false)
@@ -77,6 +90,10 @@
val bouncerErrorMessage: CharSequence?
get() = viewMediatorCallback.consumeCustomMessage()
+ init {
+ setUpLogging()
+ }
+
fun setPrimaryScrimmed(isScrimmed: Boolean) {
_primaryBouncerScrimmed.value = isScrimmed
}
@@ -132,4 +149,57 @@
fun setOnScreenTurnedOff(onScreenTurnedOff: Boolean) {
_onScreenTurnedOff.value = onScreenTurnedOff
}
+
+ /** Sets up logs for state flows. */
+ private fun setUpLogging() {
+ if (!Build.IS_DEBUGGABLE) {
+ return
+ }
+
+ primaryBouncerVisible
+ .logDiffsForTable(buffer, "", "PrimaryBouncerVisible", false)
+ .launchIn(applicationScope)
+ primaryBouncerShow
+ .map { it != null }
+ .logDiffsForTable(buffer, "", "PrimaryBouncerShow", false)
+ .launchIn(applicationScope)
+ primaryBouncerShowingSoon
+ .logDiffsForTable(buffer, "", "PrimaryBouncerShowingSoon", false)
+ .launchIn(applicationScope)
+ primaryBouncerHide
+ .logDiffsForTable(buffer, "", "PrimaryBouncerHide", false)
+ .launchIn(applicationScope)
+ primaryBouncerStartingToHide
+ .logDiffsForTable(buffer, "", "PrimaryBouncerStartingToHide", false)
+ .launchIn(applicationScope)
+ primaryBouncerStartingDisappearAnimation
+ .map { it != null }
+ .logDiffsForTable(buffer, "", "PrimaryBouncerStartingDisappearAnimation", false)
+ .launchIn(applicationScope)
+ primaryBouncerScrimmed
+ .logDiffsForTable(buffer, "", "PrimaryBouncerScrimmed", false)
+ .launchIn(applicationScope)
+ panelExpansionAmount
+ .map { (it * 1000).toInt() }
+ .logDiffsForTable(buffer, "", "PanelExpansionAmountMillis", -1)
+ .launchIn(applicationScope)
+ keyguardPosition
+ .map { it.toInt() }
+ .logDiffsForTable(buffer, "", "KeyguardPosition", -1)
+ .launchIn(applicationScope)
+ onScreenTurnedOff
+ .logDiffsForTable(buffer, "", "OnScreenTurnedOff", false)
+ .launchIn(applicationScope)
+ isBackButtonEnabled
+ .filterNotNull()
+ .logDiffsForTable(buffer, "", "IsBackButtonEnabled", false)
+ .launchIn(applicationScope)
+ showMessage
+ .map { it?.message }
+ .logDiffsForTable(buffer, "", "ShowMessage", null)
+ .launchIn(applicationScope)
+ resourceUpdateRequests
+ .logDiffsForTable(buffer, "", "ResourceUpdateRequests", false)
+ .launchIn(applicationScope)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/BouncerLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/BouncerLog.kt
new file mode 100644
index 0000000..2251a7b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/BouncerLog.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.dagger
+
+import java.lang.annotation.Documented
+import java.lang.annotation.Retention
+import java.lang.annotation.RetentionPolicy
+import javax.inject.Qualifier
+
+/** Logger for the primary and alternative bouncers. */
+@Qualifier @Documented @Retention(RetentionPolicy.RUNTIME) annotation class BouncerLog
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 74d5043..ec2e340 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -23,6 +23,8 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.log.LogBufferFactory;
+import com.android.systemui.log.table.TableLogBuffer;
+import com.android.systemui.log.table.TableLogBufferFactory;
import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.plugins.log.LogcatEchoTracker;
import com.android.systemui.plugins.log.LogcatEchoTrackerDebug;
@@ -345,6 +347,14 @@
return factory.create("BluetoothLog", 50);
}
+ /** Provides a logging buffer for the primary bouncer. */
+ @Provides
+ @SysUISingleton
+ @BouncerLog
+ public static TableLogBuffer provideBouncerLogBuffer(TableLogBufferFactory factory) {
+ return factory.create("BouncerLog", 250);
+ }
+
/**
* Provides a {@link LogBuffer} for general keyguard-related logs.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
index bb04b6b4..348d941 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
@@ -100,3 +100,46 @@
newVal
}
}
+/**
+ * Each time the Int flow is updated with a new value that's different from the previous value, logs
+ * the new value to the given [tableLogBuffer].
+ */
+fun Flow<Int>.logDiffsForTable(
+ tableLogBuffer: TableLogBuffer,
+ columnPrefix: String,
+ columnName: String,
+ initialValue: Int,
+): Flow<Int> {
+ val initialValueFun = {
+ tableLogBuffer.logChange(columnPrefix, columnName, initialValue)
+ initialValue
+ }
+ return this.pairwiseBy(initialValueFun) { prevVal, newVal: Int ->
+ if (prevVal != newVal) {
+ tableLogBuffer.logChange(columnPrefix, columnName, newVal)
+ }
+ newVal
+ }
+}
+
+/**
+ * Each time the String? flow is updated with a new value that's different from the previous value,
+ * logs the new value to the given [tableLogBuffer].
+ */
+fun Flow<String?>.logDiffsForTable(
+ tableLogBuffer: TableLogBuffer,
+ columnPrefix: String,
+ columnName: String,
+ initialValue: String?,
+): Flow<String?> {
+ val initialValueFun = {
+ tableLogBuffer.logChange(columnPrefix, columnName, initialValue)
+ initialValue
+ }
+ return this.pairwiseBy(initialValueFun) { prevVal, newVal: String? ->
+ if (prevVal != newVal) {
+ tableLogBuffer.logChange(columnPrefix, columnName, newVal)
+ }
+ newVal
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
index 9d0b833..2c299d6 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
@@ -127,11 +127,21 @@
rowInitializer(row)
}
+ /** Logs a String? change. */
+ fun logChange(prefix: String, columnName: String, value: String?) {
+ logChange(systemClock.currentTimeMillis(), prefix, columnName, value)
+ }
+
/** Logs a boolean change. */
fun logChange(prefix: String, columnName: String, value: Boolean) {
logChange(systemClock.currentTimeMillis(), prefix, columnName, value)
}
+ /** Logs a Int change. */
+ fun logChange(prefix: String, columnName: String, value: Int) {
+ logChange(systemClock.currentTimeMillis(), prefix, columnName, value)
+ }
+
// Keep these individual [logChange] methods private (don't let clients give us their own
// timestamps.)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
index 517e27a..2d412dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
@@ -27,16 +27,19 @@
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.phone.KeyguardBouncer
import com.android.systemui.statusbar.phone.KeyguardBypassController
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestCoroutineScope
import kotlinx.coroutines.yield
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
@@ -45,6 +48,7 @@
@TestableLooper.RunWithLooper
class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControllerBaseTest() {
lateinit var keyguardBouncerRepository: KeyguardBouncerRepository
+ @Mock private lateinit var bouncerLogger: TableLogBuffer
@Before
override fun setUp() {
@@ -53,7 +57,8 @@
keyguardBouncerRepository =
KeyguardBouncerRepository(
mock(com.android.keyguard.ViewMediatorCallback::class.java),
- mKeyguardUpdateMonitor
+ TestCoroutineScope(),
+ bouncerLogger,
)
super.setUp()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt
new file mode 100644
index 0000000..9970a67
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.data.repository
+
+import androidx.test.filters.SmallTest
+import com.android.keyguard.ViewMediatorCallback
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.table.TableLogBuffer
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestCoroutineScope
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardBouncerRepositoryTest : SysuiTestCase() {
+
+ @Mock private lateinit var viewMediatorCallback: ViewMediatorCallback
+ @Mock private lateinit var bouncerLogger: TableLogBuffer
+ lateinit var underTest: KeyguardBouncerRepository
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ val testCoroutineScope = TestCoroutineScope()
+ underTest =
+ KeyguardBouncerRepository(viewMediatorCallback, testCoroutineScope, bouncerLogger)
+ }
+
+ @Test
+ fun changingFlowValueTriggersLogging() = runBlocking {
+ underTest.setPrimaryHide(true)
+ verify(bouncerLogger).logChange("", "PrimaryBouncerHide", false)
+ }
+}