Merge "[Bouncer] Add bouncer log buffer." into tm-qpr-dev

This commit is contained in:
Aaron Liu
2022-12-13 00:07:56 +00:00
committed by Android (Google) Code Review
7 changed files with 221 additions and 4 deletions

View File

@@ -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 @@ constructor(
val bouncerErrorMessage: CharSequence?
get() = viewMediatorCallback.consumeCustomMessage()
init {
setUpLogging()
}
fun setPrimaryScrimmed(isScrimmed: Boolean) {
_primaryBouncerScrimmed.value = isScrimmed
}
@@ -132,4 +149,57 @@ constructor(
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)
}
}

View File

@@ -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

View File

@@ -23,6 +23,8 @@ import android.os.Looper;
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 @@ public class LogModule {
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.
*/

View File

@@ -100,3 +100,46 @@ fun Flow<Boolean>.logDiffsForTable(
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
}
}

View File

@@ -127,11 +127,21 @@ class TableLogBuffer(
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.)

View File

@@ -27,16 +27,19 @@ import com.android.systemui.keyguard.data.BouncerView
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 @@ import org.mockito.MockitoAnnotations
@TestableLooper.RunWithLooper
class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControllerBaseTest() {
lateinit var keyguardBouncerRepository: KeyguardBouncerRepository
@Mock private lateinit var bouncerLogger: TableLogBuffer
@Before
override fun setUp() {
@@ -53,7 +57,8 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle
keyguardBouncerRepository =
KeyguardBouncerRepository(
mock(com.android.keyguard.ViewMediatorCallback::class.java),
mKeyguardUpdateMonitor
TestCoroutineScope(),
bouncerLogger,
)
super.setUp()
}

View File

@@ -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)
}
}