Loading packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt +3 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import com.android.systemui.log.dagger.LongPressTouchLog import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R import com.android.systemui.statusbar.VibratorHelper import com.google.android.msdl.domain.MSDLPlayer import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher Loading @@ -66,6 +67,7 @@ constructor( private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>, private val falsingManager: Lazy<FalsingManager>, private val vibratorHelper: Lazy<VibratorHelper>, private val msdlPlayer: Lazy<MSDLPlayer>, @LongPressTouchLog private val logBuffer: LogBuffer, ) { @Composable Loading @@ -90,6 +92,7 @@ constructor( deviceEntryBackgroundViewModel.get(), falsingManager.get(), vibratorHelper.get(), msdlPlayer.get(), overrideColor, ) } Loading packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt +14 −0 Original line number Diff line number Diff line Loading @@ -311,6 +311,20 @@ class DeviceEntryHapticsInteractorTest : SysuiTestCase() { assertThat(playSuccessHaptic).isNull() } @OptIn(ExperimentalCoroutinesApi::class) @Test fun playSuccessHaptic_onDeviceEntry_fromDeviceEntryIcon() = testScope.runTest { underTest = kosmos.deviceEntryHapticsInteractor val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry) kosmos.fakeKeyguardRepository.setKeyguardDismissible(true) runCurrent() kosmos.deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon() assertThat(playSuccessHaptic).isNotNull() } // Mock dependencies for DeviceEntrySourceInteractor#deviceEntryFromBiometricSource private fun configureDeviceEntryFromBiometricSource( isFpUnlock: Boolean = false, Loading packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractor.kt +12 −7 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.shared.model.BiometricUnlockSource import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge Loading @@ -31,13 +33,19 @@ class AuthRippleInteractor constructor( deviceEntrySourceInteractor: DeviceEntrySourceInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, keyguardInteractor: KeyguardInteractor, ) { private val successfulEntryFromDeviceEntryIcon: Flow<Unit> = deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon .map { keyguardInteractor.isKeyguardDismissible.value } .filter { it } // only emit events if the keyguard is dismissible // map to Unit .map {} private val showUnlockRippleFromDeviceEntryIcon: Flow<BiometricUnlockSource> = deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { isUdfpsSupported -> if (isUdfpsSupported) { deviceEntrySourceInteractor.deviceEntryFromDeviceEntryIcon.map { BiometricUnlockSource.FINGERPRINT_SENSOR } successfulEntryFromDeviceEntryIcon.map { BiometricUnlockSource.FINGERPRINT_SENSOR } } else { emptyFlow() } Loading @@ -46,8 +54,5 @@ constructor( private val showUnlockRippleFromBiometricUnlock: Flow<BiometricUnlockSource> = deviceEntrySourceInteractor.deviceEntryFromBiometricSource val showUnlockRipple: Flow<BiometricUnlockSource> = merge( showUnlockRippleFromDeviceEntryIcon, showUnlockRippleFromBiometricUnlock, ) merge(showUnlockRippleFromDeviceEntryIcon, showUnlockRippleFromBiometricUnlock) } packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt +29 −7 Original line number Diff line number Diff line Loading @@ -16,12 +16,14 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.keyguard.logging.BiometricUnlockLogger import com.android.systemui.Flags import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.power.shared.model.WakeSleepReason import com.android.systemui.util.kotlin.FlowDumperImpl Loading Loading @@ -54,6 +56,7 @@ constructor( keyEventInteractor: KeyEventInteractor, private val logger: BiometricUnlockLogger, powerInteractor: PowerInteractor, keyguardInteractor: KeyguardInteractor, private val systemClock: SystemClock, dumpManager: DumpManager, ) : FlowDumperImpl(dumpManager) { Loading @@ -80,12 +83,7 @@ constructor( emit(recentPowerButtonPressThresholdMs * -1L - 1L) } /** * Indicates when success haptics should play when the device is entered. This always occurs on * successful fingerprint authentications. It also occurs on successful face authentication but * only if the lockscreen is bypassed. */ val playSuccessHapticOnDeviceEntry: Flow<Unit> = private val playSuccessHapticOnDeviceEntryFromBiometricSource: Flow<Unit> = deviceEntrySourceInteractor.deviceEntryFromBiometricSource .sample( combine( Loading @@ -108,7 +106,31 @@ constructor( } // map to Unit .map {} private val playSuccessHapticOnDeviceEntryFromDeviceEntryIcon: Flow<Unit> = deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon .map { keyguardInteractor.isKeyguardDismissible.value } .filter { it } // only play if the keyguard is dismissible // map to Unit .map {} /** * Indicates when success haptics should play when the device is entered. When entering via a * biometric sources, this always occurs on successful fingerprint authentications. It also * occurs on successful face authentication but only if the lockscreen is bypassed. */ val playSuccessHapticOnDeviceEntry: Flow<Unit> = if (Flags.msdlFeedback()) { merge( playSuccessHapticOnDeviceEntryFromBiometricSource, playSuccessHapticOnDeviceEntryFromDeviceEntryIcon, ) .dumpWhileCollecting("playSuccessHaptic") } else { playSuccessHapticOnDeviceEntryFromBiometricSource.dumpWhileCollecting( "playSuccessHaptic" ) } private val playErrorHapticForBiometricFailure: Flow<Unit> = merge( Loading packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractor.kt +4 −7 Original line number Diff line number Diff line Loading @@ -254,15 +254,12 @@ constructor( } .dumpWhileCollecting("deviceEntryFromBiometricSource") private val attemptEnterDeviceFromDeviceEntryIcon: MutableSharedFlow<Unit> = MutableSharedFlow() val deviceEntryFromDeviceEntryIcon: Flow<Unit> = attemptEnterDeviceFromDeviceEntryIcon .sample(keyguardInteractor.isKeyguardDismissible) .filter { it } // only send events if the keyguard is dismissible .map {} // map to Unit private val _attemptEnterDeviceFromDeviceEntryIcon: MutableSharedFlow<Unit> = MutableSharedFlow() val attemptEnterDeviceFromDeviceEntryIcon = _attemptEnterDeviceFromDeviceEntryIcon suspend fun attemptEnterDeviceFromDeviceEntryIcon() { attemptEnterDeviceFromDeviceEntryIcon.emit(Unit) _attemptEnterDeviceFromDeviceEntryIcon.emit(Unit) } private fun biometricModeIntToObject(@WakeAndUnlockMode value: Int): BiometricUnlockMode { Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt +3 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import com.android.systemui.log.dagger.LongPressTouchLog import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R import com.android.systemui.statusbar.VibratorHelper import com.google.android.msdl.domain.MSDLPlayer import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher Loading @@ -66,6 +67,7 @@ constructor( private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>, private val falsingManager: Lazy<FalsingManager>, private val vibratorHelper: Lazy<VibratorHelper>, private val msdlPlayer: Lazy<MSDLPlayer>, @LongPressTouchLog private val logBuffer: LogBuffer, ) { @Composable Loading @@ -90,6 +92,7 @@ constructor( deviceEntryBackgroundViewModel.get(), falsingManager.get(), vibratorHelper.get(), msdlPlayer.get(), overrideColor, ) } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt +14 −0 Original line number Diff line number Diff line Loading @@ -311,6 +311,20 @@ class DeviceEntryHapticsInteractorTest : SysuiTestCase() { assertThat(playSuccessHaptic).isNull() } @OptIn(ExperimentalCoroutinesApi::class) @Test fun playSuccessHaptic_onDeviceEntry_fromDeviceEntryIcon() = testScope.runTest { underTest = kosmos.deviceEntryHapticsInteractor val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry) kosmos.fakeKeyguardRepository.setKeyguardDismissible(true) runCurrent() kosmos.deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon() assertThat(playSuccessHaptic).isNotNull() } // Mock dependencies for DeviceEntrySourceInteractor#deviceEntryFromBiometricSource private fun configureDeviceEntryFromBiometricSource( isFpUnlock: Boolean = false, Loading
packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractor.kt +12 −7 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.shared.model.BiometricUnlockSource import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge Loading @@ -31,13 +33,19 @@ class AuthRippleInteractor constructor( deviceEntrySourceInteractor: DeviceEntrySourceInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, keyguardInteractor: KeyguardInteractor, ) { private val successfulEntryFromDeviceEntryIcon: Flow<Unit> = deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon .map { keyguardInteractor.isKeyguardDismissible.value } .filter { it } // only emit events if the keyguard is dismissible // map to Unit .map {} private val showUnlockRippleFromDeviceEntryIcon: Flow<BiometricUnlockSource> = deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { isUdfpsSupported -> if (isUdfpsSupported) { deviceEntrySourceInteractor.deviceEntryFromDeviceEntryIcon.map { BiometricUnlockSource.FINGERPRINT_SENSOR } successfulEntryFromDeviceEntryIcon.map { BiometricUnlockSource.FINGERPRINT_SENSOR } } else { emptyFlow() } Loading @@ -46,8 +54,5 @@ constructor( private val showUnlockRippleFromBiometricUnlock: Flow<BiometricUnlockSource> = deviceEntrySourceInteractor.deviceEntryFromBiometricSource val showUnlockRipple: Flow<BiometricUnlockSource> = merge( showUnlockRippleFromDeviceEntryIcon, showUnlockRippleFromBiometricUnlock, ) merge(showUnlockRippleFromDeviceEntryIcon, showUnlockRippleFromBiometricUnlock) }
packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt +29 −7 Original line number Diff line number Diff line Loading @@ -16,12 +16,14 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.keyguard.logging.BiometricUnlockLogger import com.android.systemui.Flags import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.power.shared.model.WakeSleepReason import com.android.systemui.util.kotlin.FlowDumperImpl Loading Loading @@ -54,6 +56,7 @@ constructor( keyEventInteractor: KeyEventInteractor, private val logger: BiometricUnlockLogger, powerInteractor: PowerInteractor, keyguardInteractor: KeyguardInteractor, private val systemClock: SystemClock, dumpManager: DumpManager, ) : FlowDumperImpl(dumpManager) { Loading @@ -80,12 +83,7 @@ constructor( emit(recentPowerButtonPressThresholdMs * -1L - 1L) } /** * Indicates when success haptics should play when the device is entered. This always occurs on * successful fingerprint authentications. It also occurs on successful face authentication but * only if the lockscreen is bypassed. */ val playSuccessHapticOnDeviceEntry: Flow<Unit> = private val playSuccessHapticOnDeviceEntryFromBiometricSource: Flow<Unit> = deviceEntrySourceInteractor.deviceEntryFromBiometricSource .sample( combine( Loading @@ -108,7 +106,31 @@ constructor( } // map to Unit .map {} private val playSuccessHapticOnDeviceEntryFromDeviceEntryIcon: Flow<Unit> = deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon .map { keyguardInteractor.isKeyguardDismissible.value } .filter { it } // only play if the keyguard is dismissible // map to Unit .map {} /** * Indicates when success haptics should play when the device is entered. When entering via a * biometric sources, this always occurs on successful fingerprint authentications. It also * occurs on successful face authentication but only if the lockscreen is bypassed. */ val playSuccessHapticOnDeviceEntry: Flow<Unit> = if (Flags.msdlFeedback()) { merge( playSuccessHapticOnDeviceEntryFromBiometricSource, playSuccessHapticOnDeviceEntryFromDeviceEntryIcon, ) .dumpWhileCollecting("playSuccessHaptic") } else { playSuccessHapticOnDeviceEntryFromBiometricSource.dumpWhileCollecting( "playSuccessHaptic" ) } private val playErrorHapticForBiometricFailure: Flow<Unit> = merge( Loading
packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractor.kt +4 −7 Original line number Diff line number Diff line Loading @@ -254,15 +254,12 @@ constructor( } .dumpWhileCollecting("deviceEntryFromBiometricSource") private val attemptEnterDeviceFromDeviceEntryIcon: MutableSharedFlow<Unit> = MutableSharedFlow() val deviceEntryFromDeviceEntryIcon: Flow<Unit> = attemptEnterDeviceFromDeviceEntryIcon .sample(keyguardInteractor.isKeyguardDismissible) .filter { it } // only send events if the keyguard is dismissible .map {} // map to Unit private val _attemptEnterDeviceFromDeviceEntryIcon: MutableSharedFlow<Unit> = MutableSharedFlow() val attemptEnterDeviceFromDeviceEntryIcon = _attemptEnterDeviceFromDeviceEntryIcon suspend fun attemptEnterDeviceFromDeviceEntryIcon() { attemptEnterDeviceFromDeviceEntryIcon.emit(Unit) _attemptEnterDeviceFromDeviceEntryIcon.emit(Unit) } private fun biometricModeIntToObject(@WakeAndUnlockMode value: Int): BiometricUnlockMode { Loading