Loading packages/SystemUI/aconfig/systemui.aconfig +0 −10 Original line number Diff line number Diff line Loading @@ -1592,16 +1592,6 @@ flag { } } flag { name: "face_message_defer_update" namespace: "systemui" description: "Only analyze the last n frames when determining whether to defer a face auth help message like low light" bug: "351863611" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "non_touchscreen_devices_bypass_falsing" namespace: "systemui" Loading packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt +5 −64 Original line number Diff line number Diff line Loading @@ -16,12 +16,9 @@ package com.android.systemui.biometrics import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.keyguard.logging.BiometricMessageDeferralLogger import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.util.time.FakeSystemClock Loading @@ -35,30 +32,16 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters @SmallTest @RunWith(ParameterizedAndroidJunit4::class) @RunWith(AndroidJUnit4::class) @android.platform.test.annotations.EnabledOnRavenwood class FaceHelpMessageDeferralTest(flags: FlagsParameterization) : SysuiTestCase() { class FaceHelpMessageDeferralTest : SysuiTestCase() { val threshold = .75f @Mock lateinit var logger: BiometricMessageDeferralLogger @Mock lateinit var dumpManager: DumpManager val systemClock = FakeSystemClock() companion object { @JvmStatic @Parameters(name = "{0}") fun getParams(): List<FlagsParameterization> { return FlagsParameterization.allCombinationsOf(Flags.FLAG_FACE_MESSAGE_DEFER_UPDATE) } } init { mSetFlagsRule.setFlagsParameterization(flags) } @Before fun setUp() { MockitoAnnotations.initMocks(this) Loading Loading @@ -130,26 +113,6 @@ class FaceHelpMessageDeferralTest(flags: FlagsParameterization) : SysuiTestCase( } @Test @DisableFlags(Flags.FLAG_FACE_MESSAGE_DEFER_UPDATE) fun testReturnsMostFrequentDeferredMessage() { val biometricMessageDeferral = createMsgDeferral(setOf(1, 2)) // WHEN there's 80% of the messages are msgId=1 and 20% is msgId=2 biometricMessageDeferral.processFrame(1) biometricMessageDeferral.processFrame(1) biometricMessageDeferral.processFrame(1) biometricMessageDeferral.processFrame(1) biometricMessageDeferral.updateMessage(1, "msgId-1") biometricMessageDeferral.processFrame(2) biometricMessageDeferral.updateMessage(2, "msgId-2") // THEN the most frequent deferred message that meets the threshold is returned assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage()) } @Test @EnableFlags(Flags.FLAG_FACE_MESSAGE_DEFER_UPDATE) fun testReturnsMostFrequentDeferredMessage_onlyAnalyzesLastNWindow() { val biometricMessageDeferral = createMsgDeferral(setOf(1, 2)) Loading @@ -165,23 +128,6 @@ class FaceHelpMessageDeferralTest(flags: FlagsParameterization) : SysuiTestCase( assertEquals("msgId-2", biometricMessageDeferral.getDeferredMessage()) } @Test @DisableFlags(Flags.FLAG_FACE_MESSAGE_DEFER_UPDATE) fun testReturnsMostFrequentDeferredMessage_analyzesAllFrames() { val biometricMessageDeferral = createMsgDeferral(setOf(1, 2)) // WHEN there's 80% of the messages are msgId=1 and 20% is msgId=2, but the last // N window only contains messages with msgId=2 repeat(80) { biometricMessageDeferral.processFrame(1) } biometricMessageDeferral.updateMessage(1, "msgId-1") systemClock.setElapsedRealtime(systemClock.elapsedRealtime() + 501L) repeat(20) { biometricMessageDeferral.processFrame(2) } biometricMessageDeferral.updateMessage(2, "msgId-2") // THEN the most frequent deferred message is returned assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage()) } @Test fun testDeferredMessage_mustMeetThreshold() { val biometricMessageDeferral = createMsgDeferral(setOf(1)) Loading @@ -207,9 +153,7 @@ class FaceHelpMessageDeferralTest(flags: FlagsParameterization) : SysuiTestCase( val biometricMessageDeferral = createMsgDeferral(setOf(1, 2)) // GIVEN two msgId=1 events processed biometricMessageDeferral.processFrame( 1, ) biometricMessageDeferral.processFrame(1) biometricMessageDeferral.updateMessage(1, "msgId-1") biometricMessageDeferral.processFrame(1) biometricMessageDeferral.updateMessage(1, "msgId-1") Loading Loading @@ -240,10 +184,7 @@ class FaceHelpMessageDeferralTest(flags: FlagsParameterization) : SysuiTestCase( @Test fun testDeferredMessage_meetThresholdWithIgnoredFrames() { val biometricMessageDeferral = createMsgDeferral( messagesToDefer = setOf(1), acquiredInfoToIgnore = setOf(4), ) createMsgDeferral(messagesToDefer = setOf(1), acquiredInfoToIgnore = setOf(4)) // WHEN more nonDeferredMessages are shown than the deferred message; HOWEVER the // nonDeferredMessages are in acquiredInfoToIgnore Loading packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt +26 −70 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import android.content.res.Resources import android.os.SystemClock.elapsedRealtime import com.android.keyguard.logging.BiometricMessageDeferralLogger import com.android.systemui.Dumpable import com.android.systemui.Flags.faceMessageDeferUpdate import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus Loading Loading @@ -94,47 +93,32 @@ open class BiometricMessageDeferral( private val systemClock: Lazy<SystemClock>, ) : Dumpable { private val faceHelpMessageDebouncer: FaceHelpMessageDebouncer? = if (faceMessageDeferUpdate()) { private val faceHelpMessageDebouncer: FaceHelpMessageDebouncer = FaceHelpMessageDebouncer( window = windowToAnalyzeLastNFrames, startWindow = 0L, shownFaceMessageFrequencyBoost = 0, threshold = threshold, ) } else { null } private val acquiredInfoToFrequency: MutableMap<Int, Int> = HashMap() private val acquiredInfoToHelpString: MutableMap<Int, String> = HashMap() private var mostFrequentAcquiredInfoToDefer: Int? = null private var totalFrames = 0 init { dumpManager.registerNormalDumpable( "${this.javaClass.name}[$id]", this, ) dumpManager.registerNormalDumpable("${this.javaClass.name}[$id]", this) } override fun dump(pw: PrintWriter, args: Array<out String>) { pw.println("messagesToDefer=$messagesToDefer") pw.println("totalFrames=$totalFrames") pw.println("threshold=$threshold") pw.println("faceMessageDeferUpdateFlagEnabled=${faceMessageDeferUpdate()}") if (faceMessageDeferUpdate()) { pw.println("windowToAnalyzeLastNFrames(ms)=$windowToAnalyzeLastNFrames") } } /** Reset all saved counts. */ fun reset() { totalFrames = 0 if (!faceMessageDeferUpdate()) { mostFrequentAcquiredInfoToDefer = null acquiredInfoToFrequency.clear() } acquiredInfoToHelpString.clear() logBuffer.reset() } Loading Loading @@ -170,46 +154,26 @@ open class BiometricMessageDeferral( } totalFrames++ if (faceMessageDeferUpdate()) { faceHelpMessageDebouncer?.let { with(faceHelpMessageDebouncer) { val helpFaceAuthStatus = HelpFaceAuthenticationStatus( msgId = acquiredInfo, msg = null, systemClock.get().elapsedRealtime() systemClock.get().elapsedRealtime(), ) if (totalFrames == 1) { // first frame it.startNewFaceAuthSession(helpFaceAuthStatus.createdAt) } it.addMessage(helpFaceAuthStatus) } } else { val newAcquiredInfoCount = acquiredInfoToFrequency.getOrDefault(acquiredInfo, 0) + 1 acquiredInfoToFrequency[acquiredInfo] = newAcquiredInfoCount if ( messagesToDefer.contains(acquiredInfo) && (mostFrequentAcquiredInfoToDefer == null || newAcquiredInfoCount > acquiredInfoToFrequency.getOrDefault( mostFrequentAcquiredInfoToDefer!!, 0 )) ) { mostFrequentAcquiredInfoToDefer = acquiredInfo startNewFaceAuthSession(helpFaceAuthStatus.createdAt) } addMessage(helpFaceAuthStatus) } logBuffer.logFrameProcessed( acquiredInfo, totalFrames, if (faceMessageDeferUpdate()) { faceHelpMessageDebouncer ?.getMessageToShow(systemClock.get().elapsedRealtime()) .getMessageToShow(systemClock.get().elapsedRealtime()) ?.msgId .toString() } else { mostFrequentAcquiredInfoToDefer?.toString() } .toString(), ) } Loading @@ -221,18 +185,10 @@ open class BiometricMessageDeferral( * [threshold] percentage. */ fun getDeferredMessage(): CharSequence? { if (faceMessageDeferUpdate()) { faceHelpMessageDebouncer?.let { val helpFaceAuthStatus = it.getMessageToShow(systemClock.get().elapsedRealtime()) with(faceHelpMessageDebouncer) { val helpFaceAuthStatus = getMessageToShow(systemClock.get().elapsedRealtime()) return acquiredInfoToHelpString[helpFaceAuthStatus?.msgId] } } else { mostFrequentAcquiredInfoToDefer?.let { if (acquiredInfoToFrequency.getOrDefault(it, 0) > (threshold * totalFrames)) { return acquiredInfoToHelpString[it] } } } return null } } Loading
packages/SystemUI/aconfig/systemui.aconfig +0 −10 Original line number Diff line number Diff line Loading @@ -1592,16 +1592,6 @@ flag { } } flag { name: "face_message_defer_update" namespace: "systemui" description: "Only analyze the last n frames when determining whether to defer a face auth help message like low light" bug: "351863611" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "non_touchscreen_devices_bypass_falsing" namespace: "systemui" Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt +5 −64 Original line number Diff line number Diff line Loading @@ -16,12 +16,9 @@ package com.android.systemui.biometrics import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.keyguard.logging.BiometricMessageDeferralLogger import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.util.time.FakeSystemClock Loading @@ -35,30 +32,16 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters @SmallTest @RunWith(ParameterizedAndroidJunit4::class) @RunWith(AndroidJUnit4::class) @android.platform.test.annotations.EnabledOnRavenwood class FaceHelpMessageDeferralTest(flags: FlagsParameterization) : SysuiTestCase() { class FaceHelpMessageDeferralTest : SysuiTestCase() { val threshold = .75f @Mock lateinit var logger: BiometricMessageDeferralLogger @Mock lateinit var dumpManager: DumpManager val systemClock = FakeSystemClock() companion object { @JvmStatic @Parameters(name = "{0}") fun getParams(): List<FlagsParameterization> { return FlagsParameterization.allCombinationsOf(Flags.FLAG_FACE_MESSAGE_DEFER_UPDATE) } } init { mSetFlagsRule.setFlagsParameterization(flags) } @Before fun setUp() { MockitoAnnotations.initMocks(this) Loading Loading @@ -130,26 +113,6 @@ class FaceHelpMessageDeferralTest(flags: FlagsParameterization) : SysuiTestCase( } @Test @DisableFlags(Flags.FLAG_FACE_MESSAGE_DEFER_UPDATE) fun testReturnsMostFrequentDeferredMessage() { val biometricMessageDeferral = createMsgDeferral(setOf(1, 2)) // WHEN there's 80% of the messages are msgId=1 and 20% is msgId=2 biometricMessageDeferral.processFrame(1) biometricMessageDeferral.processFrame(1) biometricMessageDeferral.processFrame(1) biometricMessageDeferral.processFrame(1) biometricMessageDeferral.updateMessage(1, "msgId-1") biometricMessageDeferral.processFrame(2) biometricMessageDeferral.updateMessage(2, "msgId-2") // THEN the most frequent deferred message that meets the threshold is returned assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage()) } @Test @EnableFlags(Flags.FLAG_FACE_MESSAGE_DEFER_UPDATE) fun testReturnsMostFrequentDeferredMessage_onlyAnalyzesLastNWindow() { val biometricMessageDeferral = createMsgDeferral(setOf(1, 2)) Loading @@ -165,23 +128,6 @@ class FaceHelpMessageDeferralTest(flags: FlagsParameterization) : SysuiTestCase( assertEquals("msgId-2", biometricMessageDeferral.getDeferredMessage()) } @Test @DisableFlags(Flags.FLAG_FACE_MESSAGE_DEFER_UPDATE) fun testReturnsMostFrequentDeferredMessage_analyzesAllFrames() { val biometricMessageDeferral = createMsgDeferral(setOf(1, 2)) // WHEN there's 80% of the messages are msgId=1 and 20% is msgId=2, but the last // N window only contains messages with msgId=2 repeat(80) { biometricMessageDeferral.processFrame(1) } biometricMessageDeferral.updateMessage(1, "msgId-1") systemClock.setElapsedRealtime(systemClock.elapsedRealtime() + 501L) repeat(20) { biometricMessageDeferral.processFrame(2) } biometricMessageDeferral.updateMessage(2, "msgId-2") // THEN the most frequent deferred message is returned assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage()) } @Test fun testDeferredMessage_mustMeetThreshold() { val biometricMessageDeferral = createMsgDeferral(setOf(1)) Loading @@ -207,9 +153,7 @@ class FaceHelpMessageDeferralTest(flags: FlagsParameterization) : SysuiTestCase( val biometricMessageDeferral = createMsgDeferral(setOf(1, 2)) // GIVEN two msgId=1 events processed biometricMessageDeferral.processFrame( 1, ) biometricMessageDeferral.processFrame(1) biometricMessageDeferral.updateMessage(1, "msgId-1") biometricMessageDeferral.processFrame(1) biometricMessageDeferral.updateMessage(1, "msgId-1") Loading Loading @@ -240,10 +184,7 @@ class FaceHelpMessageDeferralTest(flags: FlagsParameterization) : SysuiTestCase( @Test fun testDeferredMessage_meetThresholdWithIgnoredFrames() { val biometricMessageDeferral = createMsgDeferral( messagesToDefer = setOf(1), acquiredInfoToIgnore = setOf(4), ) createMsgDeferral(messagesToDefer = setOf(1), acquiredInfoToIgnore = setOf(4)) // WHEN more nonDeferredMessages are shown than the deferred message; HOWEVER the // nonDeferredMessages are in acquiredInfoToIgnore Loading
packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt +26 −70 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import android.content.res.Resources import android.os.SystemClock.elapsedRealtime import com.android.keyguard.logging.BiometricMessageDeferralLogger import com.android.systemui.Dumpable import com.android.systemui.Flags.faceMessageDeferUpdate import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus Loading Loading @@ -94,47 +93,32 @@ open class BiometricMessageDeferral( private val systemClock: Lazy<SystemClock>, ) : Dumpable { private val faceHelpMessageDebouncer: FaceHelpMessageDebouncer? = if (faceMessageDeferUpdate()) { private val faceHelpMessageDebouncer: FaceHelpMessageDebouncer = FaceHelpMessageDebouncer( window = windowToAnalyzeLastNFrames, startWindow = 0L, shownFaceMessageFrequencyBoost = 0, threshold = threshold, ) } else { null } private val acquiredInfoToFrequency: MutableMap<Int, Int> = HashMap() private val acquiredInfoToHelpString: MutableMap<Int, String> = HashMap() private var mostFrequentAcquiredInfoToDefer: Int? = null private var totalFrames = 0 init { dumpManager.registerNormalDumpable( "${this.javaClass.name}[$id]", this, ) dumpManager.registerNormalDumpable("${this.javaClass.name}[$id]", this) } override fun dump(pw: PrintWriter, args: Array<out String>) { pw.println("messagesToDefer=$messagesToDefer") pw.println("totalFrames=$totalFrames") pw.println("threshold=$threshold") pw.println("faceMessageDeferUpdateFlagEnabled=${faceMessageDeferUpdate()}") if (faceMessageDeferUpdate()) { pw.println("windowToAnalyzeLastNFrames(ms)=$windowToAnalyzeLastNFrames") } } /** Reset all saved counts. */ fun reset() { totalFrames = 0 if (!faceMessageDeferUpdate()) { mostFrequentAcquiredInfoToDefer = null acquiredInfoToFrequency.clear() } acquiredInfoToHelpString.clear() logBuffer.reset() } Loading Loading @@ -170,46 +154,26 @@ open class BiometricMessageDeferral( } totalFrames++ if (faceMessageDeferUpdate()) { faceHelpMessageDebouncer?.let { with(faceHelpMessageDebouncer) { val helpFaceAuthStatus = HelpFaceAuthenticationStatus( msgId = acquiredInfo, msg = null, systemClock.get().elapsedRealtime() systemClock.get().elapsedRealtime(), ) if (totalFrames == 1) { // first frame it.startNewFaceAuthSession(helpFaceAuthStatus.createdAt) } it.addMessage(helpFaceAuthStatus) } } else { val newAcquiredInfoCount = acquiredInfoToFrequency.getOrDefault(acquiredInfo, 0) + 1 acquiredInfoToFrequency[acquiredInfo] = newAcquiredInfoCount if ( messagesToDefer.contains(acquiredInfo) && (mostFrequentAcquiredInfoToDefer == null || newAcquiredInfoCount > acquiredInfoToFrequency.getOrDefault( mostFrequentAcquiredInfoToDefer!!, 0 )) ) { mostFrequentAcquiredInfoToDefer = acquiredInfo startNewFaceAuthSession(helpFaceAuthStatus.createdAt) } addMessage(helpFaceAuthStatus) } logBuffer.logFrameProcessed( acquiredInfo, totalFrames, if (faceMessageDeferUpdate()) { faceHelpMessageDebouncer ?.getMessageToShow(systemClock.get().elapsedRealtime()) .getMessageToShow(systemClock.get().elapsedRealtime()) ?.msgId .toString() } else { mostFrequentAcquiredInfoToDefer?.toString() } .toString(), ) } Loading @@ -221,18 +185,10 @@ open class BiometricMessageDeferral( * [threshold] percentage. */ fun getDeferredMessage(): CharSequence? { if (faceMessageDeferUpdate()) { faceHelpMessageDebouncer?.let { val helpFaceAuthStatus = it.getMessageToShow(systemClock.get().elapsedRealtime()) with(faceHelpMessageDebouncer) { val helpFaceAuthStatus = getMessageToShow(systemClock.get().elapsedRealtime()) return acquiredInfoToHelpString[helpFaceAuthStatus?.msgId] } } else { mostFrequentAcquiredInfoToDefer?.let { if (acquiredInfoToFrequency.getOrDefault(it, 0) > (threshold * totalFrames)) { return acquiredInfoToHelpString[it] } } } return null } }