Merge "Add DeviceEntryIconView after fingerprintProps are initialized" into main
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
index be6f022..4c76fb4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
@@ -37,7 +37,6 @@
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.ui.binder.DeviceEntryIconViewBinder
import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
@@ -78,15 +77,16 @@
if (DeviceEntryUdfpsRefactor.isEnabled) {
DeviceEntryIconView(context, null).apply {
id = R.id.device_entry_icon_view
- DeviceEntryIconViewBinder.bind(
- applicationScope,
- this,
- deviceEntryIconViewModel.get(),
- deviceEntryForegroundViewModel.get(),
- deviceEntryBackgroundViewModel.get(),
- falsingManager.get(),
- vibratorHelper.get(),
- )
+ // TODO: b/326624996 Bind the DeviceEntryIcon
+ // DeviceEntryIconViewBinder.bind(
+ // applicationScope,
+ // this,
+ // deviceEntryIconViewModel.get(),
+ // deviceEntryForegroundViewModel.get(),
+ // deviceEntryBackgroundViewModel.get(),
+ // falsingManager.get(),
+ // vibratorHelper.get(),
+ // )
}
} else {
// keyguardBottomAreaRefactor()
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
index 0c0ed77..435df5f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
@@ -51,6 +51,8 @@
* There is never more than one instance of the FingerprintProperty at any given time.
*/
interface FingerprintPropertyRepository {
+ /** Whether the fingerprint properties have been initialized yet. */
+ val propertiesInitialized: StateFlow<Boolean>
/** The id of fingerprint sensor. */
val sensorId: Flow<Int>
@@ -105,7 +107,16 @@
.stateIn(
applicationScope,
started = SharingStarted.Eagerly,
- initialValue = DEFAULT_PROPS,
+ initialValue = UNINITIALIZED_PROPS,
+ )
+
+ override val propertiesInitialized: StateFlow<Boolean> =
+ props
+ .map { it != UNINITIALIZED_PROPS }
+ .stateIn(
+ applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = props.value != UNINITIALIZED_PROPS,
)
override val sensorId: Flow<Int> = props.map { it.sensorId }
@@ -124,6 +135,17 @@
companion object {
private const val TAG = "FingerprintPropertyRepositoryImpl"
+ private val UNINITIALIZED_PROPS =
+ FingerprintSensorPropertiesInternal(
+ -2 /* sensorId */,
+ SensorProperties.STRENGTH_CONVENIENCE,
+ 0 /* maxEnrollmentsPerUser */,
+ listOf<ComponentInfoInternal>(),
+ FingerprintSensorProperties.TYPE_UNKNOWN,
+ false /* halControlsIllumination */,
+ true /* resetLockoutRequiresHardwareAuthToken */,
+ listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT)
+ )
private val DEFAULT_PROPS =
FingerprintSensorPropertiesInternal(
-1 /* sensorId */,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
index ff9cdbd..8bc0c54 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
@@ -25,6 +25,7 @@
import com.android.systemui.dagger.qualifiers.Application
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
@@ -39,6 +40,7 @@
configurationInteractor: ConfigurationInteractor,
displayStateInteractor: DisplayStateInteractor,
) {
+ val propertiesInitialized: StateFlow<Boolean> = repository.propertiesInitialized
val isUdfps: Flow<Boolean> = repository.sensorType.map { it.isUdfps() }
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index 873cc84..d0821c9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -22,11 +22,14 @@
import android.util.StateSet
import android.view.HapticFeedbackConstants
import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.common.ui.view.LongPressHandlingView
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
@@ -51,6 +54,8 @@
@JvmStatic
fun bind(
applicationScope: CoroutineScope,
+ keyguardRootView: ConstraintLayout,
+ section: DefaultDeviceEntrySection,
view: DeviceEntryIconView,
viewModel: DeviceEntryIconViewModel,
fgViewModel: DeviceEntryForegroundViewModel,
@@ -76,6 +81,23 @@
}
}
+ keyguardRootView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.positionAtUdfpsLocation.collect { supportsUdfps ->
+ section.removeViews(keyguardRootView)
+ keyguardRootView.addView(view)
+ val constraintSet = ConstraintSet().apply { clone(keyguardRootView) }
+ section.applyConstraintsAfterPropertiesInitialized(
+ constraintSet,
+ supportsUdfps,
+ )
+ constraintSet.applyTo(keyguardRootView)
+ }
+ }
+ }
+ }
+
view.repeatWhenAttached {
// Repeat on CREATED so that the view will always observe the entire
// GONE => AOD transition (even though the view may not be visible until the middle
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index 3fc9b42..d70ecce 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -26,7 +26,6 @@
import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
-import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.LockIconView
import com.android.keyguard.LockIconViewController
import com.android.systemui.Flags.keyguardBottomAreaRefactor
@@ -56,7 +55,6 @@
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val authController: AuthController,
private val windowManager: WindowManager,
private val context: Context,
@@ -69,6 +67,7 @@
private val falsingManager: Lazy<FalsingManager>,
private val vibratorHelper: Lazy<VibratorHelper>,
) : KeyguardSection() {
+ private var deviceEntryIconView: DeviceEntryIconView? = null
private val deviceEntryIconViewId = R.id.device_entry_icon_view
override fun addViews(constraintLayout: ConstraintLayout) {
@@ -80,21 +79,22 @@
notificationPanelView.removeView(it)
}
- val view =
- if (DeviceEntryUdfpsRefactor.isEnabled) {
+ if (DeviceEntryUdfpsRefactor.isEnabled) {
+ deviceEntryIconView =
DeviceEntryIconView(context, null).apply { id = deviceEntryIconViewId }
- } else {
- // keyguardBottomAreaRefactor()
- LockIconView(context, null).apply { id = R.id.lock_icon_view }
- }
- constraintLayout.addView(view)
+ } else {
+ // keyguardBottomAreaRefactor()
+ constraintLayout.addView(LockIconView(context, null).apply { id = R.id.lock_icon_view })
+ }
}
override fun bindData(constraintLayout: ConstraintLayout) {
if (DeviceEntryUdfpsRefactor.isEnabled) {
- constraintLayout.findViewById<DeviceEntryIconView?>(deviceEntryIconViewId)?.let {
+ deviceEntryIconView?.let {
DeviceEntryIconViewBinder.bind(
applicationScope,
+ constraintLayout,
+ this,
it,
deviceEntryIconViewModel.get(),
deviceEntryForegroundViewModel.get(),
@@ -111,7 +111,22 @@
}
override fun applyConstraints(constraintSet: ConstraintSet) {
- val isUdfpsSupported = keyguardUpdateMonitor.isUdfpsSupported
+ if (!DeviceEntryUdfpsRefactor.isEnabled) {
+ applyConstraints(constraintSet, authController.isUdfpsSupported)
+ }
+ }
+
+ fun applyConstraintsAfterPropertiesInitialized(
+ constraintSet: ConstraintSet,
+ isUdfpsSupported: Boolean
+ ) {
+ if (DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()) {
+ return
+ }
+ applyConstraints(constraintSet, isUdfpsSupported)
+ }
+
+ private fun applyConstraints(constraintSet: ConstraintSet, isUdfpsSupported: Boolean) {
val scaleFactor: Float = authController.scaleFactor
val mBottomPaddingPx =
context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index c9cf0c3..dc327ff 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -19,6 +19,7 @@
import android.animation.FloatEvaluator
import android.animation.IntEvaluator
import com.android.keyguard.KeyguardViewController
+import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntrySourceInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
@@ -34,11 +35,10 @@
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
@@ -60,6 +60,7 @@
private val keyguardViewController: Lazy<KeyguardViewController>,
private val deviceEntryInteractor: DeviceEntryInteractor,
private val deviceEntrySourceInteractor: DeviceEntrySourceInteractor,
+ private val fingerprintPropertyInteractor: FingerprintPropertyInteractor,
) {
private val intEvaluator = IntEvaluator()
private val floatEvaluator = FloatEvaluator()
@@ -178,21 +179,16 @@
}
}
- private val isUnlocked: Flow<Boolean> =
- deviceEntryInteractor.isUnlocked.flatMapLatest { isUnlocked ->
- if (!isUnlocked) {
- flowOf(false)
+ /** Whether the device entry icon should be positioned at the location of UDFPS. */
+ val positionAtUdfpsLocation: Flow<Boolean> =
+ fingerprintPropertyInteractor.propertiesInitialized.flatMapLatest { initialized ->
+ if (initialized) {
+ fingerprintPropertyInteractor.isUdfps
} else {
- flow {
- // delay in case device ends up transitioning away from the lock screen;
- // we don't want to animate to the unlocked icon and just let the
- // icon fade with the transition to GONE
- delay(UNLOCKED_DELAY_MS)
- emit(true)
- }
+ // Don't update the position of the icon until properties are initialized.
+ emptyFlow()
}
}
-
val iconType: Flow<DeviceEntryIconView.IconType> =
combine(
deviceEntryUdfpsInteractor.isListeningForUdfps,
@@ -245,10 +241,6 @@
DeviceEntryIconView.AccessibilityHintType.NONE
}
}
-
- companion object {
- const val UNLOCKED_DELAY_MS = 50L
- }
}
data class BurnInOffsets(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
index dc438d7..47dc70f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
@@ -83,11 +83,13 @@
val strength by collectLastValue(repository.strength)
val sensorType by collectLastValue(repository.sensorType)
val sensorLocations by collectLastValue(repository.sensorLocations)
+ val propertiesInitialized by collectLastValue(repository.propertiesInitialized)
- // Assert default properties.
- assertThat(sensorId).isEqualTo(-1)
+ // Assert uninitialized properties.
+ assertThat(sensorId).isEqualTo(-2)
assertThat(strength).isEqualTo(SensorStrength.CONVENIENCE)
assertThat(sensorType).isEqualTo(FingerprintSensorType.UNKNOWN)
+ assertThat(propertiesInitialized).isEqualTo(false)
val fingerprintProps =
listOf(
@@ -129,6 +131,7 @@
assertThat(sensorId).isEqualTo(1)
assertThat(strength).isEqualTo(SensorStrength.STRONG)
assertThat(sensorType).isEqualTo(FingerprintSensorType.REAR)
+ assertThat(propertiesInitialized).isEqualTo(true)
assertThat(sensorLocations?.size).isEqualTo(2)
assertThat(sensorLocations).containsKey("display_id_1")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
index 699284e..17d602c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
@@ -18,15 +18,16 @@
package com.android.systemui.keyguard.ui.view.layout.sections
import android.graphics.Point
+import android.testing.TestableLooper
import android.view.WindowManager
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
-import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.LockIconViewController
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
@@ -51,9 +52,9 @@
@ExperimentalCoroutinesApi
@RunWith(JUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
class DefaultDeviceEntrySectionTest : SysuiTestCase() {
- @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var authController: AuthController
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var windowManager: WindowManager
@Mock private lateinit var notificationPanelView: NotificationPanelView
@@ -61,11 +62,12 @@
@Mock private lateinit var lockIconViewController: LockIconViewController
@Mock private lateinit var falsingManager: FalsingManager
private lateinit var underTest: DefaultDeviceEntrySection
+ private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
-
+ fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
featureFlags =
@@ -73,7 +75,6 @@
underTest =
DefaultDeviceEntrySection(
TestScope().backgroundScope,
- keyguardUpdateMonitor,
authController,
windowManager,
context,
@@ -91,6 +92,7 @@
@Test
fun addViewsConditionally_migrateFlagOn() {
mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
+ mSetFlagsRule.disableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
val constraintLayout = ConstraintLayout(context, null)
underTest.addViews(constraintLayout)
assertThat(constraintLayout.childCount).isGreaterThan(0)
@@ -102,7 +104,9 @@
mSetFlagsRule.enableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
val constraintLayout = ConstraintLayout(context, null)
underTest.addViews(constraintLayout)
- assertThat(constraintLayout.childCount).isGreaterThan(0)
+
+ // No views are added initially because fingerprint properties aren't initialized yet.
+ assertThat(constraintLayout.childCount).isEqualTo(0)
}
@Test
@@ -130,7 +134,7 @@
fun applyConstraints_udfps_refactor_on() {
mSetFlagsRule.enableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
val cs = ConstraintSet()
- underTest.applyConstraints(cs)
+ underTest.applyConstraintsAfterPropertiesInitialized(cs, false)
val constraint = cs.getConstraint(R.id.device_entry_icon_view)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
index 005cac4..f95c721 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
@@ -28,6 +28,7 @@
@SysUISingleton
class FakeFingerprintPropertyRepository @Inject constructor() : FingerprintPropertyRepository {
+ override val propertiesInitialized: MutableStateFlow<Boolean> = MutableStateFlow(false)
private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1)
override val sensorId = _sensorId.asStateFlow()
@@ -50,6 +51,7 @@
sensorType: FingerprintSensorType,
sensorLocations: Map<String, SensorLocationInternal>
) {
+ propertiesInitialized.value = true
_sensorId.value = sensorId
_strength.value = strength
_sensorType.value = sensorType
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt
index 73fd999..9fe6571 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt
@@ -16,6 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
+import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntrySourceInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
@@ -50,5 +51,6 @@
keyguardViewController = { statusBarKeyguardViewManager },
deviceEntryInteractor = deviceEntryInteractor,
deviceEntrySourceInteractor = deviceEntrySourceInteractor,
+ fingerprintPropertyInteractor = fingerprintPropertyInteractor,
)
}