Merge "[Bouncer] Add bouncer log buffer." into tm-qpr-dev am: 1cd9826aa0

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20667290

Change-Id: I675db79439d5a673f9fe83309642fd7fd2f89f11
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Aaron Liu
2022-12-13 00:57:05 +00:00
committed by Automerger Merge Worker
7 changed files with 221 additions and 4 deletions

View File

@@ -16,23 +16,36 @@
package com.android.systemui.keyguard.data.repository package com.android.systemui.keyguard.data.repository
import com.android.keyguard.KeyguardUpdateMonitor import android.os.Build
import com.android.keyguard.ViewMediatorCallback import com.android.keyguard.ViewMediatorCallback
import com.android.systemui.dagger.SysUISingleton 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.BouncerShowMessageModel
import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel 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 com.android.systemui.statusbar.phone.KeyguardBouncer
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow 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 @SysUISingleton
class KeyguardBouncerRepository class KeyguardBouncerRepository
@Inject @Inject
constructor( constructor(
private val viewMediatorCallback: ViewMediatorCallback, 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. */ /** Values associated with the PrimaryBouncer (pin/pattern/password) input. */
private val _primaryBouncerVisible = MutableStateFlow(false) private val _primaryBouncerVisible = MutableStateFlow(false)
@@ -77,6 +90,10 @@ constructor(
val bouncerErrorMessage: CharSequence? val bouncerErrorMessage: CharSequence?
get() = viewMediatorCallback.consumeCustomMessage() get() = viewMediatorCallback.consumeCustomMessage()
init {
setUpLogging()
}
fun setPrimaryScrimmed(isScrimmed: Boolean) { fun setPrimaryScrimmed(isScrimmed: Boolean) {
_primaryBouncerScrimmed.value = isScrimmed _primaryBouncerScrimmed.value = isScrimmed
} }
@@ -132,4 +149,57 @@ constructor(
fun setOnScreenTurnedOff(onScreenTurnedOff: Boolean) { fun setOnScreenTurnedOff(onScreenTurnedOff: Boolean) {
_onScreenTurnedOff.value = onScreenTurnedOff _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.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.log.LogBufferFactory; 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.LogBuffer;
import com.android.systemui.plugins.log.LogcatEchoTracker; import com.android.systemui.plugins.log.LogcatEchoTracker;
import com.android.systemui.plugins.log.LogcatEchoTrackerDebug; import com.android.systemui.plugins.log.LogcatEchoTrackerDebug;
@@ -345,6 +347,14 @@ public class LogModule {
return factory.create("BluetoothLog", 50); 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. * Provides a {@link LogBuffer} for general keyguard-related logs.
*/ */

View File

@@ -100,3 +100,46 @@ fun Flow<Boolean>.logDiffsForTable(
newVal 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) rowInitializer(row)
} }
/** Logs a String? change. */
fun logChange(prefix: String, columnName: String, value: String?) {
logChange(systemClock.currentTimeMillis(), prefix, columnName, value)
}
/** Logs a boolean change. */ /** Logs a boolean change. */
fun logChange(prefix: String, columnName: String, value: Boolean) { fun logChange(prefix: String, columnName: String, value: Boolean) {
logChange(systemClock.currentTimeMillis(), prefix, columnName, value) 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 // Keep these individual [logChange] methods private (don't let clients give us their own
// timestamps.) // 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.data.repository.KeyguardBouncerRepository
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor 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.StatusBarState
import com.android.systemui.statusbar.phone.KeyguardBouncer import com.android.systemui.statusbar.phone.KeyguardBouncer
import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.KeyguardBypassController
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestCoroutineScope
import kotlinx.coroutines.yield import kotlinx.coroutines.yield
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.mock import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@@ -45,6 +48,7 @@ import org.mockito.MockitoAnnotations
@TestableLooper.RunWithLooper @TestableLooper.RunWithLooper
class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControllerBaseTest() { class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControllerBaseTest() {
lateinit var keyguardBouncerRepository: KeyguardBouncerRepository lateinit var keyguardBouncerRepository: KeyguardBouncerRepository
@Mock private lateinit var bouncerLogger: TableLogBuffer
@Before @Before
override fun setUp() { override fun setUp() {
@@ -53,7 +57,8 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle
keyguardBouncerRepository = keyguardBouncerRepository =
KeyguardBouncerRepository( KeyguardBouncerRepository(
mock(com.android.keyguard.ViewMediatorCallback::class.java), mock(com.android.keyguard.ViewMediatorCallback::class.java),
mKeyguardUpdateMonitor TestCoroutineScope(),
bouncerLogger,
) )
super.setUp() 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)
}
}