diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index a3a7135dabadc..66c57fc2a9ac7 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -23,7 +23,7 @@ android:outlineProvider="none" > + + + 16dp + + 48dp + 5 diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index e5c946156e463..d651a2159721b 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -206,5 +206,9 @@ - + + + + + diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt index 25634f009fc7d..76002d3f96939 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt @@ -34,6 +34,7 @@ import com.android.systemui.globalactions.GlobalActionsComponent import com.android.systemui.keyboard.KeyboardUI import com.android.systemui.keyboard.PhysicalKeyboardCoreStartable import com.android.systemui.keyguard.KeyguardViewMediator +import com.android.systemui.keyguard.KeyguardViewConfigurator import com.android.systemui.keyguard.data.quickaffordance.MuteQuickAffordanceCoreStartable import com.android.systemui.log.SessionTracker import com.android.systemui.media.RingtonePlayer @@ -295,4 +296,9 @@ abstract class SystemUICoreStartableModule { @IntoMap @ClassKey(AssistantAttentionMonitor::class) abstract fun bindAssistantAttentionMonitor(sysui: AssistantAttentionMonitor): CoreStartable + + @Binds + @IntoMap + @ClassKey(KeyguardViewConfigurator::class) + abstract fun bindKeyguardViewConfigurator(impl: KeyguardViewConfigurator): CoreStartable } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt new file mode 100644 index 0000000000000..05c23aefe974d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 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 + +import android.view.View +import android.view.ViewGroup +import com.android.systemui.CoreStartable +import com.android.systemui.R +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder +import com.android.systemui.keyguard.ui.view.KeyguardRootView +import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel +import com.android.systemui.shade.NotificationShadeWindowView +import com.android.systemui.statusbar.KeyguardIndicationController +import javax.inject.Inject +import kotlinx.coroutines.DisposableHandle + +/** Binds keyguard views on startup, and also exposes methods to allow rebinding if views change */ +@SysUISingleton +class KeyguardViewConfigurator +@Inject +constructor( + private val keyguardRootView: KeyguardRootView, + private val keyguardIndicationAreaViewModel: KeyguardIndicationAreaViewModel, + private val notificationShadeWindowView: NotificationShadeWindowView, + private val featureFlags: FeatureFlags, + private val indicationController: KeyguardIndicationController, +) : CoreStartable { + + private var indicationAreaHandle: DisposableHandle? = null + + override fun start() { + bindIndicationArea( + notificationShadeWindowView.requireViewById(R.id.notification_panel) as ViewGroup + ) + } + + fun bindIndicationArea(legacyParent: ViewGroup) { + indicationAreaHandle?.dispose() + + // At startup, 2 views with the ID `R.id.keyguard_indication_area` will be available. + // Disable one of them + if (featureFlags.isEnabled(Flags.MIGRATE_INDICATION_AREA)) { + legacyParent.requireViewById(R.id.keyguard_indication_area).let { + legacyParent.removeView(it) + } + } else { + keyguardRootView.findViewById(R.id.keyguard_indication_area)?.let { + keyguardRootView.removeView(it) + } + } + + indicationAreaHandle = + KeyguardIndicationAreaBinder.bind( + notificationShadeWindowView, + keyguardIndicationAreaViewModel, + indicationController + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index 3cf9a9ec5a9c6..f99b8a2458f2b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -21,6 +21,7 @@ import android.app.StatusBarManager import android.graphics.Point import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.common.ui.data.repository.ConfigurationRepository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags @@ -59,6 +60,7 @@ constructor( private val commandQueue: CommandQueue, featureFlags: FeatureFlags, bouncerRepository: KeyguardBouncerRepository, + configurationRepository: ConfigurationRepository, ) { /** * The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at @@ -172,6 +174,9 @@ constructor( /** The approximate location on the screen of the face unlock sensor, if one is available. */ val faceSensorLocation: Flow = repository.faceSensorLocation + /** Notifies when a new configuration is set */ + val configurationChange: Flow = configurationRepository.onAnyConfigurationChange + fun dozeTransitionTo(vararg states: DozeStateModel): Flow { return dozeTransitionModel.filter { states.contains(it.to) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt index a8d662c962849..7d14198bdb17e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt @@ -21,12 +21,10 @@ import android.content.Intent import android.graphics.Rect import android.graphics.drawable.Animatable2 import android.util.Size -import android.util.TypedValue import android.view.View import android.view.ViewGroup import android.view.ViewPropertyAnimator import android.widget.ImageView -import android.widget.TextView import androidx.core.view.isInvisible import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams @@ -108,14 +106,10 @@ object KeyguardBottomAreaViewBinder { activityStarter: ActivityStarter?, messageDisplayer: (Int) -> Unit, ): Binding { - val indicationArea: View = view.requireViewById(R.id.keyguard_indication_area) val ambientIndicationArea: View? = view.findViewById(R.id.ambient_indication_container) val startButton: ImageView = view.requireViewById(R.id.start_button) val endButton: ImageView = view.requireViewById(R.id.end_button) val overlayContainer: View = view.requireViewById(R.id.overlay_container) - val indicationText: TextView = view.requireViewById(R.id.keyguard_indication_text) - val indicationTextBottom: TextView = - view.requireViewById(R.id.keyguard_indication_text_bottom) val settingsMenu: LaunchableLinearLayout = view.requireViewById(R.id.keyguard_settings_button) @@ -183,7 +177,6 @@ object KeyguardBottomAreaViewBinder { } ambientIndicationArea?.alpha = alpha - indicationArea.alpha = alpha } } @@ -205,27 +198,10 @@ object KeyguardBottomAreaViewBinder { launch { viewModel.indicationAreaTranslationX.collect { translationX -> - indicationArea.translationX = translationX ambientIndicationArea?.translationX = translationX } } - launch { - combine( - viewModel.isIndicationAreaPadded, - configurationBasedDimensions.map { it.indicationAreaPaddingPx }, - ) { isPadded, paddingIfPaddedPx -> - if (isPadded) { - paddingIfPaddedPx - } else { - 0 - } - } - .collect { paddingPx -> - indicationArea.setPadding(paddingPx, 0, paddingPx, 0) - } - } - launch { configurationBasedDimensions .map { it.defaultBurnInPreventionYOffsetPx } @@ -233,22 +209,12 @@ object KeyguardBottomAreaViewBinder { viewModel.indicationAreaTranslationY(defaultBurnInOffsetY) } .collect { translationY -> - indicationArea.translationY = translationY ambientIndicationArea?.translationY = translationY } } launch { configurationBasedDimensions.collect { dimensions -> - indicationText.setTextSize( - TypedValue.COMPLEX_UNIT_PX, - dimensions.indicationTextSizePx.toFloat(), - ) - indicationTextBottom.setTextSize( - TypedValue.COMPLEX_UNIT_PX, - dimensions.indicationTextSizePx.toFloat(), - ) - startButton.updateLayoutParams { width = dimensions.buttonSizePx.width height = dimensions.buttonSizePx.height @@ -305,7 +271,7 @@ object KeyguardBottomAreaViewBinder { return object : Binding { override fun getIndicationAreaAnimators(): List { - return listOf(indicationArea, ambientIndicationArea).mapNotNull { it?.animate() } + return listOf(ambientIndicationArea).mapNotNull { it?.animate() } } override fun onConfigurationChanged() { @@ -517,12 +483,6 @@ object KeyguardBottomAreaViewBinder { return ConfigurationBasedDimensions( defaultBurnInPreventionYOffsetPx = view.resources.getDimensionPixelOffset(R.dimen.default_burn_in_prevention_offset), - indicationAreaPaddingPx = - view.resources.getDimensionPixelOffset(R.dimen.keyguard_indication_area_padding), - indicationTextSizePx = - view.resources.getDimensionPixelSize( - com.android.internal.R.dimen.text_size_small_material, - ), buttonSizePx = Size( view.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width), @@ -552,8 +512,6 @@ object KeyguardBottomAreaViewBinder { private data class ConfigurationBasedDimensions( val defaultBurnInPreventionYOffsetPx: Int, - val indicationAreaPaddingPx: Int, - val indicationTextSizePx: Int, val buttonSizePx: Size, ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt new file mode 100644 index 0000000000000..02e6765fa1d36 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2023 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.ui.binder + +import android.util.TypedValue +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.R +import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel +import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.statusbar.KeyguardIndicationController +import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch + +/** + * Binds a keyguard indication area view to its view-model. + * + * To use this properly, users should maintain a one-to-one relationship between the [View] and the + * view-binding, binding each view only once. It is okay and expected for the same instance of the + * view-model to be reused for multiple view/view-binder bindings. + */ +@OptIn(ExperimentalCoroutinesApi::class) +object KeyguardIndicationAreaBinder { + + /** Binds the view to the view-model, continuing to update the former based on the latter. */ + @JvmStatic + fun bind( + view: ViewGroup, + viewModel: KeyguardIndicationAreaViewModel, + indicationController: KeyguardIndicationController, + ): DisposableHandle { + val indicationArea: ViewGroup = view.requireViewById(R.id.keyguard_indication_area) + indicationController.setIndicationArea(indicationArea) + + val indicationText: TextView = indicationArea.requireViewById(R.id.keyguard_indication_text) + val indicationTextBottom: TextView = + indicationArea.requireViewById(R.id.keyguard_indication_text_bottom) + + view.clipChildren = false + view.clipToPadding = false + + val configurationBasedDimensions = MutableStateFlow(loadFromResources(view)) + val disposableHandle = + view.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + viewModel.alpha.collect { alpha -> + view.importantForAccessibility = + if (alpha == 0f) { + View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS + } else { + View.IMPORTANT_FOR_ACCESSIBILITY_AUTO + } + + indicationArea.alpha = alpha + } + } + + launch { + viewModel.indicationAreaTranslationX.collect { translationX -> + indicationArea.translationX = translationX + } + } + + launch { + combine( + viewModel.isIndicationAreaPadded, + configurationBasedDimensions.map { it.indicationAreaPaddingPx }, + ) { isPadded, paddingIfPaddedPx -> + if (isPadded) { + paddingIfPaddedPx + } else { + 0 + } + } + .collect { paddingPx -> + indicationArea.setPadding(paddingPx, 0, paddingPx, 0) + } + } + + launch { + configurationBasedDimensions + .map { it.defaultBurnInPreventionYOffsetPx } + .flatMapLatest { defaultBurnInOffsetY -> + viewModel.indicationAreaTranslationY(defaultBurnInOffsetY) + } + .collect { translationY -> indicationArea.translationY = translationY } + } + + launch { + configurationBasedDimensions.collect { dimensions -> + indicationText.setTextSize( + TypedValue.COMPLEX_UNIT_PX, + dimensions.indicationTextSizePx.toFloat(), + ) + indicationTextBottom.setTextSize( + TypedValue.COMPLEX_UNIT_PX, + dimensions.indicationTextSizePx.toFloat(), + ) + } + } + + launch { + viewModel.configurationChange.collect { + configurationBasedDimensions.value = loadFromResources(view) + } + } + } + } + return disposableHandle + } + + private fun loadFromResources(view: View): ConfigurationBasedDimensions { + return ConfigurationBasedDimensions( + defaultBurnInPreventionYOffsetPx = + view.resources.getDimensionPixelOffset(R.dimen.default_burn_in_prevention_offset), + indicationAreaPaddingPx = + view.resources.getDimensionPixelOffset(R.dimen.keyguard_indication_area_padding), + indicationTextSizePx = + view.resources.getDimensionPixelSize( + com.android.internal.R.dimen.text_size_small_material, + ), + ) + } + + private data class ConfigurationBasedDimensions( + val defaultBurnInPreventionYOffsetPx: Int, + val indicationAreaPaddingPx: Int, + val indicationTextSizePx: Int, + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardIndicationArea.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardIndicationArea.kt new file mode 100644 index 0000000000000..890d565b03a5f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardIndicationArea.kt @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2023 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.ui.view + +import android.content.Context +import android.text.TextUtils +import android.util.AttributeSet +import android.view.Gravity +import android.view.View +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import android.widget.LinearLayout +import com.android.systemui.R +import com.android.systemui.statusbar.phone.KeyguardIndicationTextView + +class KeyguardIndicationArea( + context: Context, + private val attrs: AttributeSet?, +) : + LinearLayout( + context, + attrs, + ) { + + init { + setId(R.id.keyguard_indication_area) + orientation = LinearLayout.VERTICAL + + addView(indicationTopRow(), LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)) + addView( + indicationBottomRow(), + LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { + gravity = Gravity.CENTER_HORIZONTAL + } + ) + } + + private fun indicationTopRow(): KeyguardIndicationTextView { + return KeyguardIndicationTextView(context, attrs).apply { + id = R.id.keyguard_indication_text + gravity = Gravity.CENTER + accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_POLITE + setTextAppearance(R.style.TextAppearance_Keyguard_BottomArea) + + val padding = R.dimen.keyguard_indication_text_padding.dp() + setPaddingRelative(padding, 0, padding, 0) + } + } + + private fun indicationBottomRow(): KeyguardIndicationTextView { + return KeyguardIndicationTextView(context, attrs).apply { + id = R.id.keyguard_indication_text_bottom + gravity = Gravity.CENTER + accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_POLITE + + setTextAppearance(R.style.TextAppearance_Keyguard_BottomArea) + setEllipsize(TextUtils.TruncateAt.END) + setAlpha(0.8f) + setMinHeight(R.dimen.keyguard_indication_text_min_height.dp()) + setMaxLines(2) + setVisibility(View.GONE) + + val padding = R.dimen.keyguard_indication_text_padding.dp() + setPaddingRelative(padding, 0, padding, 0) + } + } + + private fun Int.dp(): Int { + return context.resources.getDimensionPixelSize(this) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt new file mode 100644 index 0000000000000..abf0e80bd87a7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2023 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.ui.view + +import android.content.Context +import android.util.AttributeSet +import android.view.Gravity +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import android.widget.FrameLayout +import com.android.systemui.R + +/** Provides a container for all keyguard ui content. */ +class KeyguardRootView( + context: Context, + private val attrs: AttributeSet?, +) : + FrameLayout( + context, + attrs, + ) { + + init { + addIndicationTextArea() + } + + private fun addIndicationTextArea() { + val view = KeyguardIndicationArea(context, attrs) + addView( + view, + FrameLayout.LayoutParams( + MATCH_PARENT, + WRAP_CONTENT, + ) + .apply { + gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL + bottomMargin = R.dimen.keyguard_indication_margin_bottom.dp() + } + ) + } + + private fun Int.dp(): Int { + return context.resources.getDimensionPixelSize(this) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt index 62a1a9e16fc62..3e6f8e68891a9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt @@ -57,7 +57,7 @@ constructor( * in the wallpaper picker application. This should _always_ be `false` for the real lock screen * experience. */ - private val previewMode = MutableStateFlow(PreviewMode()) + val previewMode = MutableStateFlow(PreviewMode()) /** * ID of the slot that's currently selected in the preview that renders exclusively in the @@ -101,12 +101,6 @@ constructor( bottomAreaInteractor.alpha.distinctUntilChanged() } } - /** An observable for whether the indication area should be padded. */ - val isIndicationAreaPadded: Flow = - combine(startButton, endButton) { startButtonModel, endButtonModel -> - startButtonModel.isVisible || endButtonModel.isVisible - } - .distinctUntilChanged() /** An observable for the x-offset by which the indication area should be translated. */ val indicationAreaTranslationX: Flow = bottomAreaInteractor.clockPosition.map { it.x.toFloat() }.distinctUntilChanged() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt new file mode 100644 index 0000000000000..389cf76c47acc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2023 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.ui.viewmodel + +import com.android.systemui.doze.util.BurnInHelperWrapper +import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map + +/** View-model for the keyguard indication area view */ +@OptIn(ExperimentalCoroutinesApi::class) +class KeyguardIndicationAreaViewModel +@Inject +constructor( + private val keyguardInteractor: KeyguardInteractor, + private val bottomAreaInteractor: KeyguardBottomAreaInteractor, + private val keyguardBottomAreaViewModel: KeyguardBottomAreaViewModel, + private val burnInHelperWrapper: BurnInHelperWrapper, +) { + + /** Notifies when a new configuration is set */ + val configurationChange: Flow = keyguardInteractor.configurationChange + + /** An observable for the alpha level for the entire bottom area. */ + val alpha: Flow = keyguardBottomAreaViewModel.alpha + + /** An observable for whether the indication area should be padded. */ + val isIndicationAreaPadded: Flow = + combine(keyguardBottomAreaViewModel.startButton, keyguardBottomAreaViewModel.endButton) { + startButtonModel, + endButtonModel -> + startButtonModel.isVisible || endButtonModel.isVisible + } + .distinctUntilChanged() + /** An observable for the x-offset by which the indication area should be translated. */ + val indicationAreaTranslationX: Flow = + bottomAreaInteractor.clockPosition.map { it.x.toFloat() }.distinctUntilChanged() + + /** Returns an observable for the y-offset by which the indication area should be translated. */ + fun indicationAreaTranslationY(defaultBurnInOffset: Int): Flow { + return keyguardInteractor.dozeAmount + .map { dozeAmount -> + dozeAmount * + (burnInHelperWrapper.burnInOffset( + /* amplitude = */ defaultBurnInOffset * 2, + /* xAxis= */ false, + ) - defaultBurnInOffset) + } + .distinctUntilChanged() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 047fea123dc39..7f4c2a6e84a96 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -125,6 +125,7 @@ import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; +import com.android.systemui.keyguard.KeyguardViewConfigurator; import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; @@ -598,6 +599,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private final KeyguardTransitionInteractor mKeyguardTransitionInteractor; private final KeyguardInteractor mKeyguardInteractor; + private final KeyguardViewConfigurator mKeyguardViewConfigurator; private final @Nullable MultiShadeInteractor mMultiShadeInteractor; private final CoroutineDispatcher mMainDispatcher; private boolean mIsAnyMultiShadeExpanded; @@ -740,6 +742,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump KeyguardLongPressViewModel keyguardLongPressViewModel, KeyguardInteractor keyguardInteractor, ActivityStarter activityStarter, + KeyguardViewConfigurator keyguardViewConfigurator, KeyguardFaceAuthInteractor keyguardFaceAuthInteractor) { mInteractionJankMonitor = interactionJankMonitor; keyguardStateController.addCallback(new KeyguardStateController.Callback() { @@ -762,6 +765,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mLockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel; mKeyguardTransitionInteractor = keyguardTransitionInteractor; mKeyguardInteractor = keyguardInteractor; + mKeyguardViewConfigurator = keyguardViewConfigurator; mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { @@ -1319,7 +1323,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mKeyguardBottomArea.initFrom(oldBottomArea); mView.addView(mKeyguardBottomArea, index); initBottomArea(); - mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea); mStatusBarStateListener.onDozeAmountChanged(mStatusBarStateController.getDozeAmount(), mStatusBarStateController.getInterpolatedDozeAmount()); @@ -1361,6 +1364,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mKeyguardIndicationController.showTransientIndication(stringResourceId), mVibratorHelper, mActivityStarter); + + // Rebind (for now), as a new bottom area and indication area may have been created + mKeyguardViewConfigurator.bindIndicationArea(mKeyguardBottomArea); } @VisibleForTesting @@ -1398,7 +1404,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private void setKeyguardBottomArea(KeyguardBottomAreaView keyguardBottomArea) { mKeyguardBottomArea = keyguardBottomArea; - mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea); } void setOpenCloseListener(OpenCloseListener openCloseListener) { @@ -3023,12 +3028,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mKeyguardStatusViewController.setStatusAccessibilityImportance(mode); } - //TODO(b/254875405): this should be removed. - @Override - public KeyguardBottomAreaView getKeyguardBottomAreaView() { - return mKeyguardBottomArea; - } - @Override public void applyLaunchAnimationProgress(float linearProgress) { boolean hideIcons = LaunchAnimator.getProgress(ActivityLaunchAnimator.TIMINGS, diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt index 44c732d8082fd..1752ff6d531f5 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt @@ -32,6 +32,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.keyguard.ui.view.KeyguardRootView import com.android.systemui.privacy.OngoingPrivacyChip import com.android.systemui.scene.ui.view.WindowRootView import com.android.systemui.settings.UserTracker @@ -71,9 +72,9 @@ abstract class ShadeModule { layoutInflater.inflate(R.layout.scene_window_root, null) } else { layoutInflater.inflate(R.layout.super_notification_shade, null) - } as WindowRootView? ?: throw IllegalStateException( - "Window root view could not be properly inflated" - ) + } + as WindowRootView? + ?: throw IllegalStateException("Window root view could not be properly inflated") } @Provides @@ -89,9 +90,7 @@ abstract class ShadeModule { return root.findViewById(R.id.legacy_window_root) } return root as NotificationShadeWindowView? - ?: throw IllegalStateException( - "root view not a NotificationShadeWindowView" - ) + ?: throw IllegalStateException("root view not a NotificationShadeWindowView") } // TODO(b/277762009): Only allow this view's controller to inject the view. See above. @@ -120,6 +119,14 @@ abstract class ShadeModule { return notificationShadeWindowView.findViewById(R.id.light_reveal_scrim) } + @Provides + @SysUISingleton + fun providesKeyguardRootView( + notificationShadeWindowView: NotificationShadeWindowView, + ): KeyguardRootView { + return notificationShadeWindowView.findViewById(R.id.keyguard_root_view) + } + // TODO(b/277762009): Only allow this view's controller to inject the view. See above. @Provides @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt index f75047c2072a9..203355e71021c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt @@ -21,7 +21,6 @@ import com.android.systemui.statusbar.RemoteInputController import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.phone.HeadsUpAppearanceController -import com.android.systemui.statusbar.phone.KeyguardBottomAreaView import com.android.systemui.statusbar.phone.KeyguardStatusBarView import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController import java.util.function.Consumer @@ -120,13 +119,6 @@ interface ShadeViewController { /** Returns the StatusBarState. */ val barState: Int - /** - * Returns the bottom part of the keyguard, which contains quick affordances. - * - * TODO(b/275550429): this should be removed. - */ - val keyguardBottomAreaView: KeyguardBottomAreaView? - /** Returns the NSSL controller. */ val notificationStackScrollLayoutController: NotificationStackScrollLayoutController diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index dfaee4c674adf..5624e28204cc9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -40,7 +40,6 @@ import com.android.systemui.shade.NotificationShadeWindowView; import com.android.systemui.shade.QuickSettingsController; import com.android.systemui.shade.ShadeViewController; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; @@ -86,7 +85,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, private final HeadsUpManagerPhone mHeadsUpManager; private final AboveShelfObserver mAboveShelfObserver; private final DozeScrimController mDozeScrimController; - private final KeyguardIndicationController mKeyguardIndicationController; private final CentralSurfaces mCentralSurfaces; private final LockscreenShadeTransitionController mShadeTransitionController; private final CommandQueue mCommandQueue; @@ -115,7 +113,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, NotificationShadeWindowController notificationShadeWindowController, DynamicPrivacyController dynamicPrivacyController, KeyguardStateController keyguardStateController, - KeyguardIndicationController keyguardIndicationController, CentralSurfaces centralSurfaces, LockscreenShadeTransitionController shadeTransitionController, CommandQueue commandQueue, @@ -137,7 +134,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, mQsController = quickSettingsController; mHeadsUpManager = headsUp; mDynamicPrivacyController = dynamicPrivacyController; - mKeyguardIndicationController = keyguardIndicationController; // TODO: use KeyguardStateController#isOccluded to remove this dependency mCentralSurfaces = centralSurfaces; mShadeTransitionController = shadeTransitionController; @@ -173,7 +169,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, mNotificationPanel.getShadeNotificationPresenter().createRemoteInputDelegate()); initController.addPostInitTask(() -> { - mKeyguardIndicationController.init(); mNotifShadeEventSource.setShadeEmptiedCallback(this::maybeClosePanelForShadeEmptied); mNotifShadeEventSource.setNotifRemovedByUserCallback(this::maybeEndAmbientPulse); notificationInterruptStateProvider.addSuppressor(mInterruptSuppressor); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt index 3f1560bc5fcea..69951a5118782 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -62,6 +62,7 @@ import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit import java.util.TimeZone import java.util.concurrent.Executor +import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository import org.mockito.Mockito.`when` as whenever @RunWith(AndroidTestingRunner::class) @@ -117,6 +118,7 @@ class ClockEventControllerTest : SysuiTestCase() { commandQueue = commandQueue, featureFlags = featureFlags, bouncerRepository = bouncerRepository, + configurationRepository = FakeConfigurationRepository(), ), KeyguardTransitionInteractor(repository = transitionRepository), broadcastDispatcher, diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java index 456702b65091e..bdf6bee8ecff6 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java @@ -18,6 +18,7 @@ package com.android.keyguard; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1; +import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; @@ -42,15 +43,12 @@ import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.AuthRippleController; import com.android.systemui.doze.util.BurnInHelperKt; import com.android.systemui.dump.DumpManager; -import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository; -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository; +import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository; -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -91,10 +89,9 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase { protected @Mock ConfigurationController mConfigurationController; protected @Mock VibratorHelper mVibrator; protected @Mock AuthRippleController mAuthRippleController; - protected @Mock FeatureFlags mFeatureFlags; protected @Mock KeyguardTransitionRepository mTransitionRepository; - protected @Mock CommandQueue mCommandQueue; protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock()); + protected FakeFeatureFlags mFeatureFlags; protected LockIconViewController mUnderTest; @@ -144,6 +141,8 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase { when(mStatusBarStateController.isDozing()).thenReturn(false); when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); + mFeatureFlags = new FakeFeatureFlags(); + mFeatureFlags.set(FACE_AUTH_REFACTOR, false); mUnderTest = new LockIconViewController( mLockIconView, mStatusBarStateController, @@ -160,12 +159,7 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase { mAuthRippleController, mResources, new KeyguardTransitionInteractor(mTransitionRepository), - new KeyguardInteractor( - new FakeKeyguardRepository(), - mCommandQueue, - mFeatureFlags, - new FakeKeyguardBouncerRepository() - ), + KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(), mFeatureFlags ); } @@ -226,7 +220,7 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase { } protected void init(boolean useMigrationFlag) { - when(mFeatureFlags.isEnabled(DOZING_MIGRATION_1)).thenReturn(useMigrationFlag); + mFeatureFlags.set(DOZING_MIGRATION_1, useMigrationFlag); mUnderTest.init(); verify(mLockIconView, atLeast(1)).addOnAttachStateChangeListener(mAttachCaptor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt index 8ee7d3e862657..c9470bb41ba5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt @@ -34,6 +34,7 @@ import com.android.systemui.R import com.android.systemui.SystemUIAppComponentFactoryBase import com.android.systemui.SysuiTestCase import com.android.systemui.animation.DialogLaunchAnimator +import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository import com.android.systemui.dock.DockManagerFake import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags @@ -185,6 +186,7 @@ class CustomizationProviderTest : SysuiTestCase() { commandQueue = commandQueue, featureFlags = featureFlags, bouncerRepository = FakeKeyguardBouncerRepository(), + configurationRepository = FakeConfigurationRepository(), ), registry = mock(), lockPatternUtils = lockPatternUtils, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt index 78a65a8473dba..eb970221388b5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt @@ -7,11 +7,9 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags -import com.android.systemui.keyguard.data.repository.FakeCommandQueue -import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionStep @@ -60,13 +58,12 @@ class ResourceTrimmerTest : SysuiTestCase() { keyguardRepository.setDozeAmount(0f) keyguardRepository.setKeyguardGoingAway(false) - val keyguardInteractor = - KeyguardInteractor( - keyguardRepository, - FakeCommandQueue(), - featureFlags, - FakeKeyguardBouncerRepository() + val withDeps = + KeyguardInteractorFactory.create( + repository = keyguardRepository, + featureFlags = featureFlags, ) + val keyguardInteractor = withDeps.keyguardInteractor resourceTrimmer = ResourceTrimmer( keyguardInteractor, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index e61620beeff3e..3ea74e5822298 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -47,6 +47,7 @@ import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.AuthenticationStatus import com.android.systemui.keyguard.shared.model.DetectionStatus @@ -159,17 +160,16 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { biometricSettingsRepository = FakeBiometricSettingsRepository() deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository() trustRepository = FakeTrustRepository() - keyguardRepository = FakeKeyguardRepository() - bouncerRepository = FakeKeyguardBouncerRepository() featureFlags = FakeFeatureFlags().apply { set(FACE_AUTH_REFACTOR, true) } - fakeCommandQueue = FakeCommandQueue() - keyguardInteractor = - KeyguardInteractor( - keyguardRepository, - fakeCommandQueue, - featureFlags, - bouncerRepository + val withDeps = + KeyguardInteractorFactory.create( + featureFlags = featureFlags, ) + keyguardInteractor = withDeps.keyguardInteractor + keyguardRepository = withDeps.repository + bouncerRepository = withDeps.bouncerRepository + fakeCommandQueue = withDeps.commandQueue + alternateBouncerInteractor = AlternateBouncerInteractor( bouncerRepository = bouncerRepository, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt index 0d695aa231ccc..a4f19b415061e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt @@ -22,6 +22,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR @@ -50,6 +51,7 @@ class KeyguardInteractorTest : SysuiTestCase() { private lateinit var underTest: KeyguardInteractor private lateinit var repository: FakeKeyguardRepository private lateinit var bouncerRepository: FakeKeyguardBouncerRepository + private lateinit var configurationRepository: FakeConfigurationRepository @Before fun setUp() { @@ -59,12 +61,14 @@ class KeyguardInteractorTest : SysuiTestCase() { testScope = TestScope() repository = FakeKeyguardRepository() bouncerRepository = FakeKeyguardBouncerRepository() + configurationRepository = FakeConfigurationRepository() underTest = KeyguardInteractor( repository, commandQueue, featureFlags, bouncerRepository, + configurationRepository, ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt index fb21847cd4d1f..8f6bbc9d48d72 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt @@ -38,8 +38,6 @@ import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanc import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager -import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition @@ -48,7 +46,6 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.FakeUserTracker import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker -import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.mockito.any @@ -225,7 +222,6 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { @Mock private lateinit var animationController: ActivityLaunchAnimator.Controller @Mock private lateinit var expandable: Expandable @Mock private lateinit var launchAnimator: DialogLaunchAnimator - @Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var devicePolicyManager: DevicePolicyManager @Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger @@ -309,12 +305,10 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { underTest = KeyguardQuickAffordanceInteractor( keyguardInteractor = - KeyguardInteractor( - repository = FakeKeyguardRepository(), - commandQueue = commandQueue, - featureFlags = featureFlags, - bouncerRepository = FakeKeyguardBouncerRepository(), - ), + KeyguardInteractorFactory.create( + featureFlags = featureFlags, + ) + .keyguardInteractor, registry = FakeKeyguardQuickAffordanceRegistry( mapOf( @@ -368,11 +362,11 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled } - underTest.onQuickAffordanceTriggered( - configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS, - expandable = expandable, - slotId = "", - ) + underTest.onQuickAffordanceTriggered( + configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS, + expandable = expandable, + slotId = "", + ) if (startActivity) { if (needsToUnlockFirst) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt index 895c1cd5a1a19..1c0b06cd85b90 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt @@ -40,7 +40,6 @@ import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanc import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager -import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel @@ -53,7 +52,6 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots -import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.mockito.mock @@ -84,7 +82,6 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { @Mock private lateinit var userTracker: UserTracker @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var launchAnimator: DialogLaunchAnimator - @Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var devicePolicyManager: DevicePolicyManager @Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger @@ -168,15 +165,14 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { set(Flags.FACE_AUTH_REFACTOR, true) } + val withDeps = + KeyguardInteractorFactory.create( + featureFlags = featureFlags, + repository = repository, + ) underTest = KeyguardQuickAffordanceInteractor( - keyguardInteractor = - KeyguardInteractor( - repository = repository, - commandQueue = commandQueue, - featureFlags = featureFlags, - bouncerRepository = FakeKeyguardBouncerRepository(), - ), + keyguardInteractor = withDeps.keyguardInteractor, registry = FakeKeyguardQuickAffordanceRegistry( mapOf( diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt index 603f199b468b0..c53d4305f226a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt @@ -21,7 +21,6 @@ import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository @@ -39,7 +38,6 @@ import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.shade.data.repository.FakeShadeRepository import com.android.systemui.shade.data.repository.ShadeRepository -import com.android.systemui.statusbar.CommandQueue import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.withArgCaptor @@ -74,10 +72,10 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { private lateinit var bouncerRepository: FakeKeyguardBouncerRepository private lateinit var shadeRepository: ShadeRepository private lateinit var transitionRepository: FakeKeyguardTransitionRepository + private lateinit var featureFlags: FakeFeatureFlags // Used to verify transition requests for test output @Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository - @Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor @@ -103,11 +101,11 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN) - val featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, true) } + featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, true) } fromLockscreenTransitionInteractor = FromLockscreenTransitionInteractor( scope = testScope, - keyguardInteractor = createKeyguardInteractor(featureFlags), + keyguardInteractor = createKeyguardInteractor(), shadeRepository = shadeRepository, keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), @@ -117,7 +115,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromDreamingTransitionInteractor = FromDreamingTransitionInteractor( scope = testScope, - keyguardInteractor = createKeyguardInteractor(featureFlags), + keyguardInteractor = createKeyguardInteractor(), keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), ) @@ -126,7 +124,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromAodTransitionInteractor = FromAodTransitionInteractor( scope = testScope, - keyguardInteractor = createKeyguardInteractor(featureFlags), + keyguardInteractor = createKeyguardInteractor(), keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), ) @@ -135,7 +133,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromGoneTransitionInteractor = FromGoneTransitionInteractor( scope = testScope, - keyguardInteractor = createKeyguardInteractor(featureFlags), + keyguardInteractor = createKeyguardInteractor(), keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), ) @@ -144,7 +142,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromDozingTransitionInteractor = FromDozingTransitionInteractor( scope = testScope, - keyguardInteractor = createKeyguardInteractor(featureFlags), + keyguardInteractor = createKeyguardInteractor(), keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), ) @@ -153,7 +151,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromOccludedTransitionInteractor = FromOccludedTransitionInteractor( scope = testScope, - keyguardInteractor = createKeyguardInteractor(featureFlags), + keyguardInteractor = createKeyguardInteractor(), keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), ) @@ -162,7 +160,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromAlternateBouncerTransitionInteractor = FromAlternateBouncerTransitionInteractor( scope = testScope, - keyguardInteractor = createKeyguardInteractor(featureFlags), + keyguardInteractor = createKeyguardInteractor(), keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), ) @@ -171,7 +169,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromPrimaryBouncerTransitionInteractor = FromPrimaryBouncerTransitionInteractor( scope = testScope, - keyguardInteractor = createKeyguardInteractor(featureFlags), + keyguardInteractor = createKeyguardInteractor(), keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), keyguardSecurityModel = keyguardSecurityModel, @@ -882,13 +880,13 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { WakeSleepReason.OTHER ) - private fun createKeyguardInteractor(featureFlags: FeatureFlags): KeyguardInteractor { - return KeyguardInteractor( - keyguardRepository, - commandQueue, - featureFlags, - bouncerRepository, - ) + private fun createKeyguardInteractor(): KeyguardInteractor { + return KeyguardInteractorFactory.create( + featureFlags = featureFlags, + repository = keyguardRepository, + bouncerRepository = bouncerRepository, + ) + .keyguardInteractor } private suspend fun TestScope.runTransition(from: KeyguardState, to: KeyguardState) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt index 8a36dbc86e817..a493b1ddb93db 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt @@ -39,12 +39,11 @@ import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanc import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager -import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory import com.android.systemui.keyguard.domain.interactor.KeyguardLongPressInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor @@ -56,7 +55,6 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots -import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.FakeSharedPreferences @@ -95,7 +93,6 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { @Mock private lateinit var userTracker: UserTracker @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var launchAnimator: DialogLaunchAnimator - @Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var devicePolicyManager: DevicePolicyManager @Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher @@ -140,7 +137,6 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { ), ), ) - repository = FakeKeyguardRepository() val featureFlags = FakeFeatureFlags().apply { set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, false) @@ -149,13 +145,10 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { set(Flags.LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP, false) } - val keyguardInteractor = - KeyguardInteractor( - repository = repository, - commandQueue = commandQueue, - featureFlags = featureFlags, - bouncerRepository = FakeKeyguardBouncerRepository(), - ) + val withDeps = KeyguardInteractorFactory.create(featureFlags = featureFlags) + val keyguardInteractor = withDeps.keyguardInteractor + repository = withDeps.repository + whenever(userTracker.userHandle).thenReturn(mock()) whenever(userTracker.userId).thenReturn(10) whenever(lockPatternUtils.getStrongAuthForUser(anyInt())) @@ -549,91 +542,6 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { assertThat(value()).isEqualTo(1f) } - @Test - fun isIndicationAreaPadded() = - testScope.runTest { - repository.setKeyguardShowing(true) - val value = collectLastValue(underTest.isIndicationAreaPadded) - - assertThat(value()).isFalse() - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_START, - testConfig = - TestConfig( - isVisible = true, - isClickable = true, - icon = mock(), - canShowWhileLocked = true, - slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), - ) - ) - assertThat(value()).isTrue() - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_END, - testConfig = - TestConfig( - isVisible = true, - isClickable = true, - icon = mock(), - canShowWhileLocked = false, - slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(), - ) - ) - assertThat(value()).isTrue() - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_START, - testConfig = - TestConfig( - isVisible = false, - slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), - ) - ) - assertThat(value()).isTrue() - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_END, - testConfig = - TestConfig( - isVisible = false, - slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(), - ) - ) - assertThat(value()).isFalse() - } - - @Test - fun indicationAreaTranslationX() = - testScope.runTest { - val value = collectLastValue(underTest.indicationAreaTranslationX) - - assertThat(value()).isEqualTo(0f) - repository.setClockPosition(100, 100) - assertThat(value()).isEqualTo(100f) - repository.setClockPosition(200, 100) - assertThat(value()).isEqualTo(200f) - repository.setClockPosition(200, 200) - assertThat(value()).isEqualTo(200f) - repository.setClockPosition(300, 100) - assertThat(value()).isEqualTo(300f) - } - - @Test - fun indicationAreaTranslationY() = - testScope.runTest { - val value = - collectLastValue(underTest.indicationAreaTranslationY(DEFAULT_BURN_IN_OFFSET)) - - // Negative 0 - apparently there's a difference in floating point arithmetic - FML - assertThat(value()).isEqualTo(-0f) - val expected1 = setDozeAmountAndCalculateExpectedTranslationY(0.1f) - assertThat(value()).isEqualTo(expected1) - val expected2 = setDozeAmountAndCalculateExpectedTranslationY(0.2f) - assertThat(value()).isEqualTo(expected2) - val expected3 = setDozeAmountAndCalculateExpectedTranslationY(0.5f) - assertThat(value()).isEqualTo(expected3) - val expected4 = setDozeAmountAndCalculateExpectedTranslationY(1f) - assertThat(value()).isEqualTo(expected4) - } - @Test fun isClickable_trueWhenAlphaAtThreshold() = testScope.runTest { @@ -757,11 +665,6 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { ) } - private fun setDozeAmountAndCalculateExpectedTranslationY(dozeAmount: Float): Float { - repository.setDozeAmount(dozeAmount) - return dozeAmount * (RETURNED_BURN_IN_OFFSET - DEFAULT_BURN_IN_OFFSET) - } - private suspend fun setUpQuickAffordanceModel( position: KeyguardQuickAffordancePosition, testConfig: TestConfig, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt new file mode 100644 index 0000000000000..dff0f29091265 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2023 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.ui.viewmodel + +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.doze.util.BurnInHelperWrapper +import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory +import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(JUnit4::class) +class KeyguardIndicationAreaViewModelTest : SysuiTestCase() { + + @Mock private lateinit var burnInHelperWrapper: BurnInHelperWrapper + + private lateinit var underTest: KeyguardIndicationAreaViewModel + private lateinit var repository: FakeKeyguardRepository + + private val startButtonFlow = + MutableStateFlow( + KeyguardQuickAffordanceViewModel( + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId() + ) + ) + private val endButtonFlow = + MutableStateFlow( + KeyguardQuickAffordanceViewModel( + slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId() + ) + ) + private val alphaFlow = MutableStateFlow(1f) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + whenever(burnInHelperWrapper.burnInOffset(anyInt(), any())) + .thenReturn(RETURNED_BURN_IN_OFFSET) + + val withDeps = KeyguardInteractorFactory.create() + val keyguardInteractor = withDeps.keyguardInteractor + repository = withDeps.repository + + val bottomAreaViewModel: KeyguardBottomAreaViewModel = mock() + whenever(bottomAreaViewModel.startButton).thenReturn(startButtonFlow) + whenever(bottomAreaViewModel.endButton).thenReturn(endButtonFlow) + whenever(bottomAreaViewModel.alpha).thenReturn(alphaFlow) + underTest = + KeyguardIndicationAreaViewModel( + keyguardInteractor = keyguardInteractor, + bottomAreaInteractor = KeyguardBottomAreaInteractor(repository = repository), + keyguardBottomAreaViewModel = bottomAreaViewModel, + burnInHelperWrapper = burnInHelperWrapper, + ) + } + + @Test + fun alpha() = runTest { + val value = collectLastValue(underTest.alpha) + + assertThat(value()).isEqualTo(1f) + alphaFlow.value = 0.1f + assertThat(value()).isEqualTo(0.1f) + alphaFlow.value = 0.5f + assertThat(value()).isEqualTo(0.5f) + alphaFlow.value = 0.2f + assertThat(value()).isEqualTo(0.2f) + alphaFlow.value = 0f + assertThat(value()).isEqualTo(0f) + } + + @Test + fun isIndicationAreaPadded() = runTest { + repository.setKeyguardShowing(true) + val value = collectLastValue(underTest.isIndicationAreaPadded) + + assertThat(value()).isFalse() + startButtonFlow.value = startButtonFlow.value.copy(isVisible = true) + assertThat(value()).isTrue() + endButtonFlow.value = endButtonFlow.value.copy(isVisible = true) + assertThat(value()).isTrue() + startButtonFlow.value = startButtonFlow.value.copy(isVisible = false) + assertThat(value()).isTrue() + endButtonFlow.value = endButtonFlow.value.copy(isVisible = false) + assertThat(value()).isFalse() + } + + @Test + fun indicationAreaTranslationX() = runTest { + val value = collectLastValue(underTest.indicationAreaTranslationX) + + assertThat(value()).isEqualTo(0f) + repository.setClockPosition(100, 100) + assertThat(value()).isEqualTo(100f) + repository.setClockPosition(200, 100) + assertThat(value()).isEqualTo(200f) + repository.setClockPosition(200, 200) + assertThat(value()).isEqualTo(200f) + repository.setClockPosition(300, 100) + assertThat(value()).isEqualTo(300f) + } + + @Test + fun indicationAreaTranslationY() = runTest { + val value = collectLastValue(underTest.indicationAreaTranslationY(DEFAULT_BURN_IN_OFFSET)) + + // Negative 0 - apparently there's a difference in floating point arithmetic - FML + assertThat(value()).isEqualTo(-0f) + val expected1 = setDozeAmountAndCalculateExpectedTranslationY(0.1f) + assertThat(value()).isEqualTo(expected1) + val expected2 = setDozeAmountAndCalculateExpectedTranslationY(0.2f) + assertThat(value()).isEqualTo(expected2) + val expected3 = setDozeAmountAndCalculateExpectedTranslationY(0.5f) + assertThat(value()).isEqualTo(expected3) + val expected4 = setDozeAmountAndCalculateExpectedTranslationY(1f) + assertThat(value()).isEqualTo(expected4) + } + + private fun setDozeAmountAndCalculateExpectedTranslationY(dozeAmount: Float): Float { + repository.setDozeAmount(dozeAmount) + return dozeAmount * (RETURNED_BURN_IN_OFFSET - DEFAULT_BURN_IN_OFFSET) + } + + companion object { + private const val DEFAULT_BURN_IN_OFFSET = 5 + private const val RETURNED_BURN_IN_OFFSET = 3 + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index fe89a143e8804..41351e53e0c8b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -89,12 +89,13 @@ import com.android.systemui.flags.FeatureFlags; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; -import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository; +import com.android.systemui.keyguard.KeyguardViewConfigurator; import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository; import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel; import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel; @@ -253,6 +254,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Mock protected UserManager mUserManager; @Mock protected UiEventLogger mUiEventLogger; @Mock protected LockIconViewController mLockIconViewController; + @Mock protected KeyguardViewConfigurator mKeyguardViewConfigurator; @Mock protected KeyguardMediaController mKeyguardMediaController; @Mock protected NavigationModeController mNavigationModeController; @Mock protected NavigationBarController mNavigationBarController; @@ -342,8 +344,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mMainDispatcher = getMainDispatcher(); mKeyguardBottomAreaInteractor = new KeyguardBottomAreaInteractor( new FakeKeyguardRepository()); - mKeyguardInteractor = new KeyguardInteractor(new FakeKeyguardRepository(), mCommandQueue, - mFeatureFlags, new FakeKeyguardBouncerRepository()); + + mKeyguardInteractor = KeyguardInteractorFactory.create().getKeyguardInteractor(); SystemClock systemClock = new FakeSystemClock(); mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager, mInteractionJankMonitor, mShadeExpansionStateManager); @@ -611,6 +613,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mKeyuardLongPressViewModel, mKeyguardInteractor, mActivityStarter, + mKeyguardViewConfigurator, mKeyguardFaceAuthInteractor); mNotificationPanelViewController.initDependencies( mCentralSurfaces, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index fdfe028765efe..1724f27f63b86 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -44,7 +44,6 @@ import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeNotificationPresenter; import com.android.systemui.shade.ShadeViewController; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; @@ -122,7 +121,6 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { mock(NotificationShadeWindowController.class), mock(DynamicPrivacyController.class), mKeyguardStateController, - mock(KeyguardIndicationController.class), mCentralSurfaces, mock(LockscreenShadeTransitionController.class), mCommandQueue, diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt index d9ee08157c847..813597a8b5769 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt @@ -28,12 +28,10 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR import com.android.systemui.keyguard.WakefulnessLifecycle -import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory import com.android.systemui.shade.ShadeFoldAnimator import com.android.systemui.shade.ShadeViewController -import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.unfold.util.FoldableDeviceStates @@ -80,8 +78,6 @@ class FoldAodAnimationControllerTest : SysuiTestCase() { @Mock lateinit var viewTreeObserver: ViewTreeObserver - @Mock private lateinit var commandQueue: CommandQueue - @Mock lateinit var shadeFoldAnimator: ShadeFoldAnimator @Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor @@ -111,15 +107,10 @@ class FoldAodAnimationControllerTest : SysuiTestCase() { onActionStarted.run() } - keyguardRepository = FakeKeyguardRepository() val featureFlags = FakeFeatureFlags().apply { set(FACE_AUTH_REFACTOR, true) } - val keyguardInteractor = - KeyguardInteractor( - repository = keyguardRepository, - commandQueue = commandQueue, - featureFlags = featureFlags, - bouncerRepository = FakeKeyguardBouncerRepository(), - ) + val withDeps = KeyguardInteractorFactory.create(featureFlags = featureFlags) + val keyguardInteractor = withDeps.keyguardInteractor + keyguardRepository = withDeps.repository // Needs to be run on the main thread runBlocking(IMMEDIATE) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt index ca83d49b19cad..3fbbeda8f74d0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt @@ -39,12 +39,10 @@ import com.android.systemui.common.shared.model.Text import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags -import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.user.UserSwitchDialogController -import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.telephony.data.repository.FakeTelephonyRepository import com.android.systemui.telephony.domain.interactor.TelephonyInteractor @@ -97,7 +95,6 @@ class UserInteractorTest : SysuiTestCase() { @Mock private lateinit var dialogShower: UserSwitchDialogController.DialogShower @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver - @Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor private lateinit var underTest: UserInteractor @@ -126,8 +123,9 @@ class UserInteractorTest : SysuiTestCase() { set(Flags.FULL_SCREEN_USER_SWITCHER, false) set(Flags.FACE_AUTH_REFACTOR, true) } + val reply = KeyguardInteractorFactory.create(featureFlags = featureFlags) + keyguardRepository = reply.repository userRepository = FakeUserRepository() - keyguardRepository = FakeKeyguardRepository() telephonyRepository = FakeTelephonyRepository() val testDispatcher = StandardTestDispatcher() testScope = TestScope(testDispatcher) @@ -142,13 +140,7 @@ class UserInteractorTest : SysuiTestCase() { applicationContext = context, repository = userRepository, activityStarter = activityStarter, - keyguardInteractor = - KeyguardInteractor( - repository = keyguardRepository, - commandQueue = commandQueue, - featureFlags = featureFlags, - bouncerRepository = FakeKeyguardBouncerRepository(), - ), + keyguardInteractor = reply.keyguardInteractor, manager = manager, headlessSystemUserMode = headlessSystemUserMode, applicationScope = testScope.backgroundScope, diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt index fd8c6c76720b5..9cb26e05887df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt @@ -32,11 +32,8 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.common.shared.model.Text import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags -import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.telephony.data.repository.FakeTelephonyRepository import com.android.systemui.telephony.domain.interactor.TelephonyInteractor @@ -80,13 +77,11 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() { @Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver - @Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor private lateinit var underTest: StatusBarUserChipViewModel private val userRepository = FakeUserRepository() - private val keyguardRepository = FakeKeyguardRepository() private lateinit var guestUserInteractor: GuestUserInteractor private lateinit var refreshUsersScheduler: RefreshUsersScheduler @@ -250,12 +245,8 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() { repository = userRepository, activityStarter = activityStarter, keyguardInteractor = - KeyguardInteractor( - repository = keyguardRepository, - commandQueue = commandQueue, - featureFlags = featureFlags, - bouncerRepository = FakeKeyguardBouncerRepository(), - ), + KeyguardInteractorFactory.create(featureFlags = featureFlags) + .keyguardInteractor, featureFlags = featureFlags, manager = manager, headlessSystemUserMode = headlessSystemUserMode, diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt index 91550844cecac..e3f9fac278155 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt @@ -30,11 +30,9 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.common.shared.model.Text import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags -import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.telephony.data.repository.FakeTelephonyRepository import com.android.systemui.telephony.domain.interactor.TelephonyInteractor @@ -79,7 +77,6 @@ class UserSwitcherViewModelTest : SysuiTestCase() { @Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver - @Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor private lateinit var underTest: UserSwitcherViewModel @@ -112,7 +109,6 @@ class UserSwitcherViewModelTest : SysuiTestCase() { ) } - keyguardRepository = FakeKeyguardRepository() val refreshUsersScheduler = RefreshUsersScheduler( applicationScope = testScope.backgroundScope, @@ -140,38 +136,35 @@ class UserSwitcherViewModelTest : SysuiTestCase() { set(Flags.FULL_SCREEN_USER_SWITCHER, false) set(Flags.FACE_AUTH_REFACTOR, true) } + val reply = KeyguardInteractorFactory.create(featureFlags = featureFlags) + keyguardRepository = reply.repository + underTest = UserSwitcherViewModel( - userInteractor = - UserInteractor( - applicationContext = context, - repository = userRepository, - activityStarter = activityStarter, - keyguardInteractor = - KeyguardInteractor( - repository = keyguardRepository, - commandQueue = commandQueue, - featureFlags = featureFlags, - bouncerRepository = FakeKeyguardBouncerRepository(), - ), - featureFlags = featureFlags, - manager = manager, - headlessSystemUserMode = headlessSystemUserMode, - applicationScope = testScope.backgroundScope, - telephonyInteractor = - TelephonyInteractor( - repository = FakeTelephonyRepository(), - ), - broadcastDispatcher = fakeBroadcastDispatcher, - keyguardUpdateMonitor = keyguardUpdateMonitor, - backgroundDispatcher = testDispatcher, - activityManager = activityManager, - refreshUsersScheduler = refreshUsersScheduler, - guestUserInteractor = guestUserInteractor, - uiEventLogger = uiEventLogger, - ), - guestUserInteractor = guestUserInteractor, - ) + userInteractor = + UserInteractor( + applicationContext = context, + repository = userRepository, + activityStarter = activityStarter, + keyguardInteractor = reply.keyguardInteractor, + featureFlags = featureFlags, + manager = manager, + headlessSystemUserMode = headlessSystemUserMode, + applicationScope = testScope.backgroundScope, + telephonyInteractor = + TelephonyInteractor( + repository = FakeTelephonyRepository(), + ), + broadcastDispatcher = fakeBroadcastDispatcher, + keyguardUpdateMonitor = keyguardUpdateMonitor, + backgroundDispatcher = testDispatcher, + activityManager = activityManager, + refreshUsersScheduler = refreshUsersScheduler, + guestUserInteractor = guestUserInteractor, + uiEventLogger = uiEventLogger, + ), + guestUserInteractor = guestUserInteractor, + ) } @Test @@ -323,7 +316,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() { setUsers(count = 2) val isFinishRequested = mutableListOf() val job = - launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } + launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } assertThat(isFinishRequested.last()).isFalse() underTest.onCancelButtonClicked() diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt similarity index 100% rename from packages/SystemUI/tests/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt rename to packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt new file mode 100644 index 0000000000000..c7ca7ceb516ef --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2023 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.domain.interactor + +import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository +import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.keyguard.data.repository.FakeCommandQueue +import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository + +/** + * Simply put, I got tired of adding a constructor argument and then having to tweak dozens of + * files. This should alleviate some of the burden by providing defaults for testing. + */ +object KeyguardInteractorFactory { + + @JvmOverloads + @JvmStatic + fun create( + featureFlags: FakeFeatureFlags = createFakeFeatureFlags(), + repository: FakeKeyguardRepository = FakeKeyguardRepository(), + commandQueue: FakeCommandQueue = FakeCommandQueue(), + bouncerRepository: FakeKeyguardBouncerRepository = FakeKeyguardBouncerRepository(), + configurationRepository: FakeConfigurationRepository = FakeConfigurationRepository(), + ): WithDependencies { + return WithDependencies( + repository = repository, + commandQueue = commandQueue, + featureFlags = featureFlags, + bouncerRepository = bouncerRepository, + configurationRepository = configurationRepository, + KeyguardInteractor( + repository = repository, + commandQueue = commandQueue, + featureFlags = featureFlags, + bouncerRepository = bouncerRepository, + configurationRepository = configurationRepository, + ) + ) + } + + /** Provide defaults, otherwise tests will throw an error */ + fun createFakeFeatureFlags(): FakeFeatureFlags { + return FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, false) } + } + + data class WithDependencies( + val repository: FakeKeyguardRepository, + val commandQueue: FakeCommandQueue, + val featureFlags: FakeFeatureFlags, + val bouncerRepository: FakeKeyguardBouncerRepository, + val configurationRepository: FakeConfigurationRepository, + val keyguardInteractor: KeyguardInteractor, + ) +}