Merge "[Bouncer] Add bouncer log buffer." into tm-qpr-dev
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.)
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user